HEX
Server: LiteSpeed
System: Linux atali.colombiahosting.com.co 5.14.0-570.12.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Tue May 13 06:11:55 EDT 2025 x86_64
User: coopserp (1713)
PHP: 8.2.29
Disabled: dl,exec,passthru,proc_open,proc_close,shell_exec,memory_limit,system,popen,curl_multi_exec,show_source,symlink,link,leak,listen,diskfreespace,tmpfile,ignore_user_abord,highlight_file,source,show_source,fpaththru,virtual,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix,posix_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setid,posix_times,posix_ttyname,posix_uname,proc_get_status,proc_nice,proc_terminate
Upload Files
File: /home/coopserp/public_html/main.tar
promo.php000064400000003456151526414160006426 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Promo{
	static function update_notice(){
		if(defined('SOFTACULOUS_PLUGIN_UPDATE_NOTICE')){
			return;
		}

		$to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);

		if(empty($to_update_plugins)){
			return;
		}

		/* translators: %1$s is replaced with a "string" of name of plugins, and %2$s is replaced with "string" which can be "is" or "are" based on the count of the plugin */
		$msg = sprintf(__('New versions of %1$s %2$s available. Updating ensures better performance, security, and access to the latest features.', 'speedycache'), '<b>'.esc_html(implode(', ', $to_update_plugins)).'</b>', (count($to_update_plugins) > 1 ? 'are' : 'is')) . ' <a class="button button-primary" href='.esc_url(admin_url('plugins.php?plugin_status=upgrade')).'>Update Now</a>';

		define('SOFTACULOUS_PLUGIN_UPDATE_NOTICE', true); // To make sure other plugins don't return a Notice
		echo '<div class="notice notice-info is-dismissible" id="speedycache-plugin-update-notice">
			<p>'.$msg. '</p>
		</div>';

		wp_register_script('speedycache-update-notice', '', ['jquery'], '', true);
		wp_enqueue_script('speedycache-update-notice');
		wp_add_inline_script('speedycache-update-notice', 'jQuery("#speedycache-plugin-update-notice").on("click", function(e){
			let target = jQuery(e.target);

			if(!target.hasClass("notice-dismiss")){
				return;
			}

			var data;
			
			// Hide it
			jQuery("#speedycache-plugin-update-notice").hide();
			
			// Save this preference
			jQuery.post("'.admin_url('admin-ajax.php?action=speedycache_close_update_notice').'&security='.wp_create_nonce('speedycache_promo_nonce').'", data, function(response) {
				//alert(response);
			});
		});');
	}
	
}admin.php000064400000045724151526414160006366 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

// Show menu with error if speedy cache is installed but is older than 1.1.0
// as after that we dont short circuit the free version
if(!defined('SPEEDYCACHE_VERSION') || version_compare(SPEEDYCACHE_VERSION, '1.1.1') < 0){
	add_action('admin_menu', 'speedycachepro_add_menu');
	return; // Return else going forward will break things.
}

add_action('speedycache_license_tmpl', '\SpeedyCache\SettingsPage::license_tab');
add_action('speedycache_db_tmpl', '\SpeedyCache\SettingsPage::db_tab');
add_action('speedycache_pro_logs_tmpl', '\SpeedyCache\SettingsPage::logs');
add_action('speedycache_pro_stats_tmpl', '\SpeedyCache\SettingsPage::stats');
add_action('speedycache_image_optm_tmpl', '\SpeedyCache\SettingsPage::image_optm');
add_action('speedycache_bloat_tmpl', '\SpeedyCache\SettingsPage::bloat_tab');
add_action('speedycache_object_cache_tmpl', '\SpeedyCache\SettingsPage::object_tab');

include_once SPEEDYCACHE_PRO_DIR . '/main/premium.php';

if(defined('SPEEDYCACHE_PRO') && file_exists(SPEEDYCACHE_PRO_DIR . '/main/image.php')){
	\SpeedyCache\Image::init();
	add_action('wp_ajax_speedycache_download_cwebp', '\SpeedyCache\Image::download_cwebp');
	add_action('add_meta_boxes_attachment', 'speedycache_pro_media_metabox');
}

add_action('admin_init', 'speedycache_pro_schedule_test_event');
add_action('admin_notices', 'speedycache_pro_notices');
add_filter('softaculous_expired_licenses', 'speedycache_pro_plugins_expired');
add_action('admin_enqueue_scripts', 'speedycache_pro_enqueue_admin_scripts');

// ----- AJAX ACTIONS ----- //
add_action('wp_ajax_speedycache_statics_ajax_request', 'speedycache_pro_img_stats');
add_action('wp_ajax_speedycache_optimize_image_ajax_request', 'speedycache_pro_optimize_image');
add_action('wp_ajax_speedycache_update_image_settings', 'speedycache_pro_save_img_settings');
add_action('wp_ajax_speedycache_update_image_list_ajax_request', 'speedycache_pro_list_imgs');
add_action('wp_ajax_speedycache_revert_image_ajax_request', 'speedycache_pro_revert_img');
add_action('wp_ajax_speedycache_img_revert_all', 'speedycache_pro_revert_all_imgs');
add_action('wp_ajax_speedycache_verify_license', 'speedycache_pro_verify_license');
add_action('wp_ajax_speedycache_copy_test_settings', 'speedycache_pro_copy_test_settings');
add_action('wp_ajax_speedycache_dismiss_test_notice','speedycache_pro_dismiss_test_notice');
add_action('wp_ajax_speedycache_pro_dismiss_expired_licenses', 'speedycache_pro_dismiss_expired_licenses');

function speedycachepro_add_menu(){
	add_menu_page('SpeedyCache Settings', 'SpeedyCache', 'activate_plugins', 'speedycache', 'speedycachepro_menu_page');
}

function speedycachepro_menu_page(){
	echo '<div style="color: #333;padding: 50px;text-align: center;">
		<h1 style="font-size: 2em;margin-bottom: 10px;">Update Speedycache to Latest Version!</h>
		<p style=" font-size: 16px;margin-bottom: 20px; font-weight:400;">SpeedyCache Pro depends on the free version of SpeedyCache, so you need to update the free version to use SpeedyCache without any issue.</p>
		<a href="'.admin_url('plugin-install.php?s=speedycache&tab=search').'" style="text-decoration: none;font-size:16px;">Install Now</a>
	</div>';
}

function speedycache_pro_img_stats(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	if(!class_exists('\SpeedyCache\Image')){
		wp_send_json_error(__('The file required to Process Image optimization is not present', 'speedycache'));
	}

	$res = \SpeedyCache\Image::statics_data();
	wp_send_json($res);
}

function speedycache_pro_optimize_image(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	if(!class_exists('\SpeedyCache\Image')){
		wp_send_json_error(__('The file required to Process Image optimization is not present', 'speedycache'));
	}
	
	$id = null;
	if(!empty($_POST['img_id'])){
		$id = (int) sanitize_text_field(wp_unslash($_POST['img_id']));
		
		if(empty($id)){
			wp_send_json_error('Empty Image ID');
		}
	}
	

	$res = \SpeedyCache\Image::optimize_single($id);
	$res[1] = isset($res[1]) ? $res[1] : '';
	$res[2] = isset($res[2]) ? $res[2] : '';
	$res[3] = isset($res[3]) ? $res[3] : '';
	
	$response = array(
		'message' => $res[0],
		'success' => $res[1],
		'id' => $res[2],
		'percentage' => $res[3],
	);
	
	wp_send_json($response);
}

function speedycache_pro_save_img_settings(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');
	
	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	global $speedycache;

	$settings = speedycache_optpost('settings');
	
	foreach($settings as $key => $setting){		
		$new_key = str_replace('img_', '', $key);
		
		$settings[$new_key] = $setting;
		unset($settings[$key]);
	}

	$speedycache->image['settings'] = $settings;
	
	if(update_option('speedycache_img', $speedycache->image['settings'])){
		wp_send_json_success();
	}
	
	wp_send_json_error();
}

function speedycache_pro_list_imgs(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');
	
	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	$query_images_args = array();
	$query_images_args['offset'] = intval(speedycache_optget('page')) * intval(speedycache_optget('per_page'));
	$query_images_args['order'] = 'DESC';
	$query_images_args['orderby'] = 'ID';
	$query_images_args['post_type'] = 'attachment';
	$query_images_args['post_mime_type'] = array('image/jpeg', 'image/png', 'image/gif');
	$query_images_args['post_status'] = 'inherit';
	$query_images_args['posts_per_page'] = speedycache_optget('per_page');
	$query_images_args['meta_query'] = array(
								array(
									'key' => 'speedycache_optimisation',
									'compare' => 'EXISTS'
									)
								);

	$query_images_args['s'] = speedycache_optget('search');

	if(!empty($_GET['filter'])){
		if(speedycache_optget('filter') == 'error_code'){
			
			$filter = array(
				'key' => 'speedycache_optimisation',
				'value' => base64_encode('"error_code"'),
				'compare' => 'LIKE'
			);

			$filter_second = array(
				'key' => 'speedycache_optimisation',
				'compare' => 'NOT LIKE'
			);

			array_push($query_images_args['meta_query'], $filter);
			array_push($query_images_args['meta_query'], $filter_second);
		}
	}

	$result = array(
		'content' => \SpeedyCache\Image::list_content($query_images_args),
		'result_count' => \SpeedyCache\Image::count_query($query_images_args)
	);

	wp_send_json($result);
}

function speedycache_pro_revert_img(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must Be admin');
	}

	global $speedycache;

	if(!empty($_GET['id'])){
		$speedycache->image['id'] = (int) speedycache_optget('id');
	}

	wp_send_json(\SpeedyCache\Image::revert());
}

function speedycache_pro_revert_all_imgs(){
	check_ajax_referer('speedycache_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	\SpeedyCache\Image::revert_all();
}


function speedycache_pro_verify_license(){

	if(!wp_verify_nonce($_GET['security'], 'speedycache_license')){
		wp_send_json_error(__('Security Check Failed', 'speedycache'));
	}
	
	if(!current_user_can('manage_options')){
		wp_send_json_error(__('You do not have required permission.', 'speedycache'));
	}
	
	global $speedycache;

	$license = sanitize_key($_GET['license']);
	
	if(empty($license)){
		wp_send_json_error(__('The license key was not submitted', 'speedycache'));
	}
	
	$resp = wp_remote_get(SPEEDYCACHE_API.'license.php?license='.$license.'&url='.rawurlencode(site_url()), array('timeout' => 30));
	
	if(!is_array($resp)){
		wp_send_json_error(__('The response was malformed<br>'.var_export($resp, true), 'speedycache'));
	}

	$json = json_decode($resp['body'], true);

	// Save the License
	if(empty($json['license'])){
		wp_send_json_error(__('The license key is invalid', 'speedycache'));
	}
	
	$speedycache->license = $json;
	update_option('speedycache_license', $json, false);
	
	wp_send_json_success();
}

function speedycache_pro_enqueue_admin_scripts(){
	wp_enqueue_style('speedycache-admin-pro', SPEEDYCACHE_PRO_URL . '/assets/css/admin.css', [], SPEEDYCACHE_PRO_VERSION);
	wp_enqueue_script('speedycache-admin-pro', SPEEDYCACHE_PRO_URL . '/assets/js/admin.js', [], SPEEDYCACHE_PRO_VERSION);
	wp_localize_script('speedycache-admin-pro', 'speedycache_pro_ajax', [
		'url' => admin_url('admin-ajax.php'),
		'nonce' => wp_create_nonce('speedycache_pro_ajax_nonce'),
		'premium' => defined('SPEEDYCACHE_PRO'),
	]);
}

// Sets speedycache settings to our predefined defaults.
function speedycache_pro_copy_test_settings(){
	check_ajax_referer('speedycache_pro_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}

	global $speedycache;

	$test_settings = ['minify_html' => true, 'delay_js' => true, 'render_blocking' => true, 'minify_js' => true, 'critical_images' => true, 'lazy_load' => true, 'delay_js_mode' => 'selected', 'delay_js_scripts' => ['fbevents.js', 'google-analytics.com', 'adsbygoogle.js', 'googletagmanager.com', 'fbq(', "ga( '", "ga('", '/gtm.js', '/gtag/js', 'gtag(', '/gtm-', '/gtm.']];
	
	$speedycache->options = array_merge($speedycache->options, $test_settings);
	
	update_option('speedycache_options', $speedycache->options);
	delete_option('speedycache_test_results');
	
	wp_send_json_success(__('Settings applied successfully.', 'speedycache-pro'));
}	

function speedycache_pro_dismiss_test_notice(){
	check_ajax_referer('speedycache_pro_ajax_nonce', 'security');

	if(!current_user_can('manage_options')){
		wp_die('Must be admin');
	}
	
	delete_option('speedycache_test_results');
}

function speedycache_pro_schedule_test_event() {
	$install_time = get_option('speedycache_free_installed', 0);
	$event_executed = get_option('speedycache_test_executed', 0);
	if($install_time && !$event_executed){
		if(($install_time + WEEK_IN_SECONDS) < time()){
			$event_time = time() + DAY_IN_SECONDS;
		} else {
			$event_time = $install_time + WEEK_IN_SECONDS;
		}

		if(!wp_next_scheduled('speedycache_test_event')){
			wp_schedule_single_event($event_time, 'speedycache_test_event');
		}
	}
}

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

	$current_screen = get_current_screen();
	if(!isset($current_screen->id) || strpos($current_screen->id, 'speedycache') === false){
		return;
	}

	$test_results = get_option('speedycache_test_results');

	if(empty($test_results)){
		return;
	}
	
	$old_score = $test_results['old_score'];
	$new_score = $test_results['new_score'];

	$stroke_old = !empty($old_score) ? 100 - $old_score : 0;
	$stroke_new = !empty($new_score) ? 100 - $new_score : 0;

	$old_color = speedycache_pro_get_score_color($old_score);
	$new_color = speedycache_pro_get_score_color($new_score);

	echo '<div class="notice notice-success is-dismissible speedycache-test-notice">
	<p class="speedycache-notice-title"><strong>'.esc_html__('Speed Test Results:', 'speedycache-pro').'</strong></p>

	<div class="speedycache-test-chart-wrap">
		<!-- Before Optimization -->
		<div class="speedycache-donut-wrap speedycache-before-optimization">
			<svg width="150" height="150" viewBox="0 0 40 40" class="speedycache-donut">
				<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="'.esc_attr($old_color[1]).'"></circle>
				<circle class="speedycache-donut-segment" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3" stroke-linecap="round" stroke-dasharray="'.esc_attr($old_score).' '.esc_attr($stroke_old).'" stroke-dashoffset="25" style="stroke:'.esc_attr($old_color[0]).';"></circle>
				<g class="speedycache-test-donut-text">
					<text y="55%" transform="translate(0, 2)">
						<tspan x="50%" text-anchor="middle" class="speedycache-donut-percent" style="fill:'.esc_attr($old_color[2]).';">'.esc_attr($old_score).'</tspan>
					</text>
				</g>
			</svg>
			<p class="speedycache-donut-label">'.esc_html__('Before Optimization', 'speedycache-pro').'</p>
		</div>

		<!-- After Optimization -->
		<div class="speedycache-donut-wrap speedycache-after-optimization">
			<svg width="150" height="150" viewBox="0 0 40 40" class="speedycache-donut">
				<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="'.esc_attr($new_color[1]).'"></circle>
				<circle class="speedycache-donut-segment" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3" stroke-linecap="round" stroke-dasharray="'.esc_attr($new_score).' '.esc_attr($stroke_new).'" stroke-dashoffset="25" style="stroke:'.esc_attr($new_color[0]).';"></circle>
				<g class="speedycache-test-donut-text">
					<text y="55%" transform="translate(0, 2)">
						<tspan x="50%" text-anchor="middle" class="speedycache-donut-percent" style="fill:'.esc_attr($new_color[2]).';">'.esc_attr($new_score).'</tspan>
					</text>
				</g>
			</svg>
			<p class="speedycache-donut-label">'.esc_html__('After Optimization', 'speedycache-pro').'</p>
		</div>
	</div>

	<div class="speedycache-test-action">
		'.esc_html__('Want to enable the SpeedyCache settings used for this test?', 'speedycache-pro').' 
		<button class="speedycache-enable-btn speedycache-copy-test-settings">'.esc_html__('Enable Now', 'speedycache-pro').'</button>
	</div>

	<button type="button" class="notice-dismiss speedycache-custom-dismiss">
		<span class="screen-reader-text">'.esc_html__('Dismiss this notice.', 'speedycache-pro').'</span>
	</button>
	</div>';
}

function speedycache_pro_plugins_expired($plugins){
	global $speedycache;
	
	if(!empty($speedycache->license) && empty($speedycache->license['active'])){
		$plugins[] = 'SpeedyCache';
	}

	return $plugins;
}

function speedycache_pro_notices(){
	global $speedycache;
	
	if(!current_user_can('activate_plugins')){
		return;
	}

	$current_screen = get_current_screen();
	
	// Test result notice
	if(isset($current_screen->id) && strpos($current_screen->id, 'speedycache') !== false){
		speedycache_pro_test_results_notice();
	}
	
	// If the license is active then we do not need to show any notice.
	if(!empty($speedycache->license) && empty($speedycache->license['active'])){
		speedycache_pro_expiry_notice();
	}
	
}

function speedycache_pro_expiry_notice(){
	global $speedycache;

	// The combined notice for all Softaculous plugin to show that the license has expired
	$dismissed_at = get_option('softaculous_expired_licenses', 0);
	$expired_plugins = apply_filters('softaculous_expired_licenses', []);
	if(
		!empty($expired_plugins) && 
		is_array($expired_plugins) && 
		!defined('SOFTACULOUS_EXPIRY_LICENSES') && 
		(empty($dismissed_at) || ($dismissed_at + WEEK_IN_SECONDS) < time())
	){

		define('SOFTACULOUS_EXPIRY_LICENSES', true); // To make sure other plugins don't return a Notice
		echo '<div class="notice notice-error is-dismissible" id="speedycache-pro-expiry-notice">
				<p>'.sprintf(__('Your %1$s plugin license has %2$sExpired%3$s. Please renew your license for uninterrupted updates and support.', 'speedycache-pro'), 
				esc_html(implode(', ', $expired_plugins)),
				'<font style="color:red;"><b>',
				'</b></font>'
				). '</p>
			</div>';

		wp_register_script('speedycache-pro-expiry-notice', '', array('jquery'), SPEEDYCACHE_PRO_VERSION, true );
		wp_enqueue_script('speedycache-pro-expiry-notice');
		wp_add_inline_script('speedycache-pro-expiry-notice', '
		jQuery(document).ready(function(){
			jQuery("#speedycache-pro-expiry-notice").on("click", ".notice-dismiss", function(e){
				e.preventDefault();
				let target = jQuery(e.target);

				let jEle = target.closest("#speedycache-pro-expiry-notice");
				jEle.slideUp();

				jQuery.post("'.admin_url('admin-ajax.php').'", {
					security : "'.wp_create_nonce('speedycache_expiry_notice').'",
					action: "speedycache_pro_dismiss_expired_licenses",
				}, function(res){
					if(!res["success"]){
						alert(res["data"]);
					}
				}).fail(function(data){
					alert("There seems to be some issue dismissing this alert");
				});
			});
		})');
	}
}

function speedycache_pro_get_score_color($score) {

	$score_color_map = [
		0   => ['#c00', '#c003', '#c00'], // Red
		50  => ['#fa3', '#ffa50036', '#fa3'], // Orange
		90  => ['#0c6', '#00cc663b', '#080'], // Green
	];

	if ($score >= 0 && $score < 50) {
		return $score_color_map[0];
	} elseif ($score >= 50 && $score < 90) {
		return $score_color_map[50];
	} else {
		return $score_color_map[90];
	}
}

function speedycache_pro_media_metabox($post){
	
	if(empty($post)){
		return;
	}
	
	$allowed_img_types = [
		'image/png',
		'image/jpg',
		'image/jpeg',
	];
	
	if(!in_array($post->post_mime_type, $allowed_img_types)){
		return;
	}

	add_meta_box( 
		'speedycache-optm-img',
		__('SpeedyCache Image Optimization', 'speedycache-pro'),
		'speedycache_pro_img_optm_metabox',
		'attachment',
		'side',
		'default'
		);
}

function speedycache_pro_img_optm_metabox($post){
	
	if(empty($post)){
		echo 'No Post data';
		return;
	}
	
	$optimized_data = get_post_meta($post->ID, 'speedycache_optimisation', true);
	
	if(!empty($optimized_data)){
		$optimized_data = base64_decode($optimized_data);
		$optimized_data = json_decode($optimized_data, true);
		
		if(!empty($optimized_data) && !empty($optimized_data[0]) && !empty($optimized_data[0]['file']) && file_exists($optimized_data[0]['file'])){
			esc_html_e('Image has already been optimized', 'speedycache-pro');
			return;
		}
	}

	echo '<button class="button" id="speedycache-optm-attachment" data-id="'.esc_attr($post->ID).'">'.esc_html__('Optimize this Image', 'speedycache-pro').'</button>';
	
	wp_register_script('speedycache-img-optm-meta-box', '', array('jquery'), '', true);
	wp_enqueue_script('speedycache-img-optm-meta-box');
	wp_add_inline_script('speedycache-img-optm-meta-box', 'jQuery(document).ready(function(){
		jQuery("#speedycache-optm-attachment").on("click", function(e){
			e.preventDefault();
			
			let attachment_id = jQuery(e.target).data("id"),
			nonce = "'.wp_create_nonce('speedycache_ajax_nonce').'";
			
			jQuery.ajax({
				url : "'.esc_url(admin_url('admin-ajax.php')).'",
				method : "POST",
				data : {
					"action":"speedycache_optimize_image_ajax_request",
					"security": nonce,
					"img_id": attachment_id,
				},
				success: function(res){
					if(res.success){
						window.location.reload();
					}
				}
			});
			
		})
	})');
}

function speedycache_pro_dismiss_expired_licenses(){
	check_admin_referer('speedycache_expiry_notice', 'security');

	if(!current_user_can('activate_plugins')){
		wp_send_json_error(__('You do not have required access to do this action', 'speedycache-pro'));
	}

	update_option('softaculous_expired_licenses', time());
	wp_send_json_success();
}cdn.php000064400000021241151526414160006026 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class CDN{
	static $allowed_types = [];
	static $cdn_url = '';
	static $specific = [];
	static $excludes = [];
	
	static function rewrite(&$content){
		global $speedycache;

		self::$cdn_url = $speedycache->cdn['cdn_url'];
		self::$allowed_types = $speedycache->cdn['file_types'];
		self::$excludes = $speedycache->cdn['excludekeywords'];
		self::$specific = $speedycache->cdn['keywords'];

		if(empty(self::$cdn_url) || empty(self::$allowed_types)){
			return;
		}

		// Define the patterns to match specific URLs (e.g., images, CSS, JS)
		$base_dir = defined('SITEPAD') ? 'sitepad-data' : 'wp-content';

		if (defined('SITEPAD')){
			global $sitepad;
			$site_inc_url = $sitepad['url'] . '/site-inc';
		} else {
			$site_inc_url = home_url('/wp-includes/');
		}

		$patterns = [
			'/' . preg_quote(home_url("/{$base_dir}/uploads/"), '/') . '([^"\']+)/i',
			'/'.  preg_quote($site_inc_url, '/') . '([^"\']+)/i',
			'/' . preg_quote(home_url("/{$base_dir}/themes/"), '/') . '([^"\']+)/i',
			'/' . preg_quote(defined('SP_PLUGIN_URL') ? SP_PLUGIN_URL : home_url('/wp-content/plugins/'), '/') . '([^"\']+)/i',
			'/' . preg_quote(home_url("/{$base_dir}/cache/"), '/') . '([^"\']+)/i',
		];

		// Loop through each pattern and replace only URLs with the specified file types
		foreach($patterns as $pattern){
			$content = preg_replace_callback($pattern, '\SpeedyCache\CDN::replace_urls', $content);
		}
	}
	
	static function replace_urls($matches) {
		global $speedycache;

		// Get the file extension
		$file_url = preg_replace('/\?.*$/', '', $matches[0]);

		if(empty($file_url)){
			$file_url = $matches[0];
		}
		
		$file_url = trim($file_url, '/');

		if(self::is_excluded($file_url)){
			return $matches[0];
		}
		
		// To rewrite just some specific files only
		if(!empty(self::$specific) && is_array(self::$specific)){
			$is_specific = false;

			foreach(self::$specific as $required_source){
				if(preg_match('/'.preg_quote($required_source).'/i', $file_url)){
					$is_specific = true;
					break;
				}
			}

			if(empty($is_specific)){
				return $matches[0];
			}	
		}
		
		$file_extension = self::get_file_extension($file_url);
		
		// Check if the file extension is in the allowed list
		if(in_array(strtolower($file_extension), self::$allowed_types)){
			$home_url = home_url();

			// Rewrite the URL to use the CDN
			return str_replace($home_url, self::$cdn_url, $matches[0]);
		}

		// If not in the allowed list, return the original URL
		return $matches[0];
	}
	
	static function get_file_extension($url) {
		
		$url = strtok($url, ' ');
		$url = strtok($url, '?');
		
		return strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
	}
	
	static function is_excluded($url){

		if(empty($url)){
			return false;
		}
		
		// array check if just to make sure things dont break for 1.2.0 in which we rewrote the plugin
		if(empty(self::$excludes) || !is_array(self::$excludes)){
			return false;
		}
		
		foreach(self::$excludes as $exclude){
			if(preg_match('/'.preg_quote($exclude).'/i', $url)){				
				return true;
			}
		}

		return false;	
	}
	
	static function purge(){
		global $speedycache;

		// Only cloudflare and Bunny can be purged, that too we only want that to happen if CDN is enabled.
		if(
			empty($speedycache->cdn['enabled']) || 
			empty($speedycache->cdn['cdn_key']) || 
			empty($speedycache->cdn['cdn_type']) || 
			$speedycache->cdn['cdn_type'] == 'other'
		){
			return;
		}

		if($speedycache->cdn['cdn_type'] == 'bunny'){
			self::purge_bunny($speedycache->cdn);
		}elseif($speedycache->cdn['cdn_type'] == 'cloudflare'){
			self::purge_cloudflare($speedycache->cdn);
		}
		
	}
	
	// Get unique pull ID to purge cache on CDN 
	static function bunny_get_pull_id(&$cdn){
		global $speedycache;

		$pull_zone = $cdn['cdn_url']; // bunny cdn calls it cdn url as pull zone
		$access_key = $cdn['cdn_key'];
		
		if(empty($access_key)){
			return array('success' => false, 'message' => __('Bunny CDN Access Key not found', 'speedycache'));
		}
		
		$options = array(
			'headers' => array(
				'AccessKey' => $access_key,
				'accept' => 'application/json'
			)
		);

		$res = wp_remote_get('https://api.bunny.net/pullzone', $options);

		if(is_wp_error($res) || empty($res)){
			if(empty($res)){
				return array('success' => false, 'message' => __('Bunny CDN retuned an empty response', 'speedycache'));
			}
			
			return array('success' => false, 'message' => 'Something Went Wrong: ' . $res->get_error_message());
		}
		
		$res_code = wp_remote_retrieve_response_code($res);
		
		if(substr($res_code, 0, 1) != 2){
			return array('success' => false, 'message' => __('Something Went Wrong: Getting Pull ID was unsuccessful ', 'speedycache') . $res_code);
		}
		
		$res_body = wp_remote_retrieve_body($res);
		
		if(empty($res_body)){
			return array('success' => false, 'message' => __('Bunny CDN pull ID response body is empty', 'speedycache'));
		}

		$res_body = json_decode($res_body, true);
		
		foreach($res_body as $pull_zones){
			if($pull_zones['OriginUrl'] == $cdn['origin_url']){
				return $pull_zones['Id'];
			}
		}

		return array('success' => false, 'message' => __('Bunny Pull Zone not found', 'speedycache'));
	}
	
	static function purge_bunny($cdn){

		if(empty($cdn['cdn_key']) || empty($cdn['cdn_url'])){
			return false;
		}

		$pull_zone = $cdn['cdn_url']; // bunny cdn calls it cdn url as pull zone
		$access_key = $cdn['cdn_key'];
		$pull_id = !empty($cdn['bunny_pull_id']) ? $cdn['bunny_pull_id'] : '';

		if(empty($access_key) || empty($pull_id)){
			return false;
		}

		$options = array(
			'headers' => array(
				'AccessKey' => $access_key,
				'content-type' => 'application/json'
			)
		);

		$res = wp_remote_post('https://api.bunny.net/pullzone/'.$pull_id.'/purgeCache', $options);
		
		if(is_wp_error($res) || empty($res)){
			if(empty($res)){
				return __('Bunny CDN retuned an empty response', 'speedycache');
			}
			
			return 'Something Went Wrong: ' . $res->get_error_message();
		}

		$res_code = wp_remote_retrieve_response_code($res);
		
		if($res_code != 204){
			return esc_html__('Something Went Wrong: Purge was unsuccessful with response code of ', 'speedycache') . $res_code;
		}

		return esc_html__('Success: Bunny CDN purged successfully', 'speedycache');

	}
	
	static function cloudflare_zone_id(&$cdn){
		
		if(empty($cdn['cdn_key'])){
			return false;
		}

		$api_token = $cdn['cdn_key'];
		$domain = parse_url(home_url(), PHP_URL_HOST);

		$url = 'https://api.cloudflare.com/client/v4/zones?name='.$domain;

		$args = [
			'headers' => [
				'Authorization' => 'Bearer ' . $api_token,
				'Content-Type' => 'application/json',
			],
		];

		$response = wp_remote_get($url, $args);

		if (is_wp_error($response)) {
			return 'Error: ' . $response->get_error_message();
		}

		$body = json_decode(wp_remote_retrieve_body($response), true);

		if($body && isset($body['result'][0]['id'])){
			return $body['result'][0]['id']; // This is the Zone ID
		}
		
		return false;
	}
	
	static function purge_cloudflare($cdn){
		
		if(empty($cdn['cloudflare_zone_id']) || empty($cdn['cdn_key'])){
			return;
		}
		
		$zone_id = $cdn['cloudflare_zone_id'];
		$api_token = $cdn['cdn_key'];

		$url = 'https://api.cloudflare.com/client/v4/zones/'.$zone_id.'/purge_cache';

		$args = [
			'headers' => [
				'Authorization' => 'Bearer ' . $api_token,
				'Content-Type'  => 'application/json',
			],
			'body' => json_encode([
				'purge_everything' => true, // Set to true to purge all cache
			]),
		];

		$response = wp_remote_post($url, $args);

		if (is_wp_error($response)) {
			return 'Error: ' . $response->get_error_message();
		}

		$body = json_decode(wp_remote_retrieve_body($response), true);

		if ($body && isset($body['success']) && $body['success'] === true) {
			return esc_html__('Cloudflare cache purged successfully.', 'speedycache');
		}

		return 'Failed to purge Cloudflare cache. ' . (isset($body['errors'][0]['message']) ? $body['errors'][0]['message'] : '');
	}

	// Users can add a custom CDN URL in Head Tag
	static function cdn_preconnect(){
		global $speedycache;

		if(empty($speedycache->options['status']) || empty($speedycache->cdn['enabled']) || empty($speedycache->cdn['cdn_url'])){
			return;
		}
		
		if($speedycache->cdn['cdn_type'] == 'other' || $speedycache->cdn['cdn_type'] == 'bunny'){
			echo '<link rel="preconnect" href="'. esc_url($speedycache->cdn['cdn_url']) .'" crossorigin="anonymous">';
		}
	}
	
}
js.php000064400000013574151526414160005710 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT');
}

use \SpeedyCache\Util;

class JS{
	
	// Depericated since 1.2.0
	// do not use it just to prevent site from breaking.
	static function init(){
		
	}
	static function minify(&$content){
		global $speedycache;
		
		if(!class_exists('\SpeedyCache\Enhanced')){
			return;
		}

		preg_match_all('/<script\s+([^>]+[\s"\'])?src\s*=\s*[\'"]\s*?(?<url>[^\'"]+\.js(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?><\/script>/is', $content, $tags, PREG_SET_ORDER);

		if(empty($tags)){
			return;
		}

		if(empty($_SERVER['HTTP_HOST'])){
			return;
		}

		$site_host = str_replace('www.', '', sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])));
		$site_url = site_url();

		foreach($tags as $tag){

			if(empty($tag['url'])){
				continue;
			}

			$url = $tag['url'];
			
			if(self::is_excluded($url)) continue;

			// We don't want to minify already minified js
			if(strpos($url, '.min.js') !== FALSE){
				continue;
			}

			// We wont process any css that is not present on this WordPress install
			if(strpos($url, $site_host) === FALSE){
				continue;
			}

			$file_path = Util::url_to_path($url);

			if(!file_exists($file_path)){
				continue;
			}

			$file_name = self::file_name($file_path);
			
			if(empty($speedycache->enhanced)){
				\SpeedyCache\Enhanced::init();
			}
			
			$js = file_get_contents($file_path);
			$js = \SpeedyCache\Enhanced::minify_js($js);

			$asset_path = Util::cache_path('assets');
			if(!is_dir($asset_path)){
				mkdir($asset_path, 0755, true);
				touch($asset_path . 'index.html');
			}

			$minified_path = $asset_path.$file_name;

			file_put_contents($minified_path, $js);

			$minified_url = Util::path_to_url($minified_path);
			$content = str_replace($tag['url'], $minified_url, $content);
			
			// TODO: check if there is a preload.
		}
	}
	
	static function combine_head(&$content){
		global $speedycache;

		if (preg_match('/<head.*?>(.*?)<\/head>/is', $content, $head_section)) {			
			$head = preg_replace( '/<!--(.*)-->/Uis', '', $head_section[1]);

			// Regex pattern to match script tags with src attribute in the head section
			preg_match_all('/<script\s+([^>]+[\s"\'])?src\s*=\s*[\'"]\s*?(?<url>[^\'"]+\.js(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?><\/script>/is', $head, $tags, PREG_SET_ORDER);
			
			if(empty($tags)){
				return;
			}

			if(empty($_SERVER['HTTP_HOST'])){
				return;
			}
			
			$site_host = str_replace('www.', '', sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])));
			$site_url = site_url();
			
			$tags = array_reverse($tags);
			
			// There is no sense in combinining just 2 files.
			if(count($tags) < 2){
				return;
			}
			
			$combined_js = '';
			$prev_tag = '';

			foreach($tags as $tag){

				if(empty($tag['url'])){
					continue;
				}
				
				// We wont combine modules.
				if(!empty($tag[1]) && strpos($tag[1], 'module')){
					continue;
				}

				$url = $tag['url'];

				if(self::is_excluded($url)) continue;
				
				// We wont process any js that is not present on this WordPress install
				if(strpos($url, $site_host) === FALSE){
					continue;
				}
				
				$file_path = Util::url_to_path($url);

				if(!file_exists($file_path) || !is_readable($file_path)){
					continue;
				}

				$combined_js = file_get_contents($file_path) . "\n" . $combined_js;
				
				// Removing the JS which has already been combined, as we will add the combined file at the top after title.
				if(!empty($prev_tag)){
					$content = str_replace($prev_tag, '', $content);
				}
				
				// We remove the previous tag, in current iteration, so at last we have a tag to replace wirh the combined script.
				$prev_tag = $tag[0];
			}
			
			if(empty($combined_js)){
				return;
			}
			
			if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['minify_js'])){
				if(empty($speedycache->enhanced)){
					\SpeedyCache\Enhanced::init();
				}

				$combined_js = \SpeedyCache\Enhanced::minify_js($combined_js);
			}

			// Creating Combined file name
			$file_name = md5($combined_js);
			$file_name = substr($file_name, 0, 16) . '-combined.js';
			
			$asset_path = Util::cache_path('assets');
			if(!is_dir($asset_path)){
				mkdir($asset_path, 0755, true);
				touch($asset_path . 'index.html');
			}

			$combined_path = $asset_path.$file_name;

			file_put_contents($combined_path, $combined_js);
			$final_url = Util::path_to_url($combined_path);

			// Injecting the Combined JS
			if(!empty($prev_tag)){
				$content = str_replace($prev_tag, '<script src="'.esc_url($final_url).'" />', $content);
				return;
			}

			$content = str_replace('</title>', "</title>\n".'<script src="'.esc_url($final_url).'"/>', $content);
		
		}
	}
	
	static function file_name($path){
		$file_hash = md5_file($path);
		$file_name = substr($file_hash, 0, 16) . '-' . basename($path);

		return $file_name;
	}
	
	static function combine_body(&$content){
		global $speedycache;
		
		\SpeedyCache\Enhanced::init();
		\SpeedyCache\Enhanced::set_html($content);

		if(!empty($speedycache->options['minify_js'])){
			$content = \SpeedyCache\Enhanced::combine_js_in_footer(true);
		}else{
			$content = \SpeedyCache\Enhanced::combine_js_in_footer();
		}
	}
	
	static function is_excluded($url){
		$excludes = get_option('speedycache_exclude', []);
		
		// Combining JQUERY will mess up the site.
		if(strpos($url, 'jquery')){
			return true;
		}

		if(empty($excludes)){
			return false;
		}

		foreach($excludes as $exclude){
			if(empty($exclude['type'])){
				continue;
			}

			if($exclude['type'] !== 'js'){
				continue;
			}

			if(empty($exclude['content'])){
				continue;
			}

			if(preg_match('/'.preg_quote($exclude['content'], '/').'/', $url)){
				return true;
			}
		}

		return false;
	}
}
gravatar.php000064400000006172151526414160007077 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt');
}

class Gravatar{
	
	// Gets gravatar data
	static function get_avatar_data($args, $id_or_email){

		if(empty($args) || empty($args['found_avatar'])){
			return $args;
		}
		
		if(empty($args['url'])){
			return $args;
		}
		
		// Path to Gravatars
		$path = \SpeedyCache\Util::cache_path('gravatars');

		if(!is_dir($path)){
			mkdir($path, 0755, true);
			touch($path . 'index.html');
		}

		$email_hash = self::get_email_hash($id_or_email);
		if(empty($email_hash)){
			$email_hash = 'default';
		}

		$file_name = $email_hash . 'x' . $args['size'] . '.jpg';
		$file = $path . $file_name;

		if(file_exists($file)){
			$url = self::convert_path_to_link($path) . $file_name;

			$args['url'] = esc_url($url);
			return $args;
		}

		$res = wp_remote_get($args['url']);

		if(empty($res) || is_wp_error($res)){
			return $args;
		}

		if(empty($res['body'])){
			return $args;
		}

		// If we fail to write return the same URL;
		if(!file_put_contents($file, $res['body'])){
			return $args;
		}

		$url = self::convert_path_to_link($path) . $file_name;

		$args['url'] = esc_url($url);

		return $args;
	}
	
	// Gets the Email hash which is used in the URL.
	static function get_email_hash($id_or_email){

		if(is_numeric($id_or_email)){
			$user = get_user_by('id', $id_or_email);

			if(empty($user) || !is_a($user, 'WP_User')){
				return false;
			}

		} elseif(is_a($id_or_email, 'WP_User')){
			$user = $id_or_email;
		} elseif(is_a($id_or_email, 'WP_Post')){
			$user = get_user_by('id', (int) $id_or_email->post_author);
		} elseif(is_a($id_or_email, 'WP_Comment')){
			if(!empty($id_or_email->user_id)){
				$user = get_user_by('id', (int) $id_or_email->user_id);
			}

			if(empty($user) && !empty($id_or_email->comment_author_email)){
				$id_or_email = $id_or_email->comment_author_email;
			}

			if(is_a($id_or_email, 'WP_Comment')){
				return false;
			}
		}
		
		if(!empty($user) && is_a($user, 'WP_User')){
			$id_or_email = $user->user_email;
		}
		
		// We need an email which should be a string if something else is being passed then just return
		if(!is_string($id_or_email)){
			return false;
		}

		$email_hash = md5(strtolower(trim($id_or_email)));
		
		return $email_hash;
	}
	
	// Deletes all the gravatar stored
	static function delete(){
		$path = \SpeedyCache\Util::cache_path('gravatars');
		
		if(!file_exists($path)){
			return;
		}

		$files = scandir($path);
		
		if(empty($files)){
			return __('No file present to delete', 'speedycache');
		}
		
		foreach($files as $file){
			// We dont want to delete index.html or any directory.
			if(file_exists($path . $file) && !is_dir($path . $file) && $file != 'index.html'){
				@unlink($path . $file);
			}
		}

		return __('Gravatar files deleted', 'speedycache');
	}
	
	static function convert_path_to_link($path){
		preg_match('/\/cache\/speedycache\/.+/', $path, $out);
		$prefix_link = str_replace(array('http:', 'https:'), '', content_url());

		return $prefix_link . $out[0];
	}

}
install.php000064400000013277151526414160006742 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Install{
	
	static function activate(){
		self::default_settings();
		update_option('siteseo_version', SITESEO_VERSION);
	}

	static function deactivate(){
		flush_rewrite_rules();
	}

	static function uninstall(){
		flush_rewrite_rules();
		delete_option('siteseo_version');
		delete_option('siteseo_toggle');
		delete_option('siteseo_titles_option_name');
		delete_option('siteseo_social_option_name');
		delete_option('siteseo_advanced_option_name');
		delete_option('siteseo_instant_indexing_option_name');
		delete_option('siteseo_xml_sitemap_option_name');
		delete_option('siteseo_google_analytics_option_name');
		delete_option('siteseo_dismiss_intro');
	}
	
	static function action_links($links, $file){
		
		if($file === plugin_basename(SITESEO_FILE)){
				
			$links['siteseo-settings'] = '<a href="'.admin_url('admin.php?page=siteseo').'">'. __('Settings', 'siteseo').'</a>';
			$links['siteseo-wizard'] = '<a href="'.admin_url('?page=siteseo-onboarding').'">'. __('Configuration Wizard', 'siteseo').'</a>';
			$links['siteseo-docs-link'] = '<a href="https://siteseo.io/docs/" target="_blank"">'. __('Docs', 'siteseo').'</a>';
		
		}
		
		return $links;	
	}

	static function default_settings(){
		// We do not need to set defaults if we just upgrading the plugin
		$current_version = get_option('siteseo_version');
		if(!empty($current_version)){
			return;
		}
		
		$titles_metas = get_option('siteseo_titles_option_name', []);
		$social_settings = get_option('siteseo_social_option_name', []);
		$advanced_settings = get_option('siteseo_advanced_option_name', []);
		$sitemap_settings = get_option('siteseo_xml_sitemap_option_name', []);
		
		$toggle_settings = [
			'toggle-titles' => true,
			'toggle-xml-sitemap' => true,
			'toggle-instant-indexing' => true,
			'toggle-advanced' => true,
			'toggle-social' => true,
			'toggle-google-analytics' => true
		];

		// Titles and Metas
		$titles_metas['titles_sep'] = '-';
		$titles_metas['titles_home_site_title'] = !isset($titles_metas['titles_home_site_title']) ? '%%sitetitle%%' : $titles_metas['titles_home_site_title'];
		$titles_metas['titles_home_site_desc'] = !isset($titles_metas['titles_home_site_desc']) ? '%%tagline%%' : $titles_metas['titles_home_site_desc'];
		
		$post_types = siteseo_post_types();
		if(!empty($post_types) && is_array($post_types)){
			$post_types = array_keys($post_types);

			foreach($post_types as $post_type){
				$titles_metas['titles_single_titles'][$post_type]['title'] = !isset($titles_metas['titles_single_titles'][$post_type]['title']) ? '%%post_title%% %%sep%% %%sitetitle%%' : $titles_metas['titles_single_titles'][$post_type]['title'];
				$titles_metas['titles_single_titles'][$post_type]['description'] = !isset($titles_metas['titles_single_titles'][$post_type]['description']) ? '%%post_excerpt%% ' : $titles_metas['titles_single_titles'][$post_type]['description'];
			}
		}
		
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		if(!empty($taxonomies) && is_array($taxonomies)){
			$taxonomies = array_keys($taxonomies);
			
			foreach($taxonomies as $taxonomy){
				$titles_metas['titles_tax_titles'][$taxonomy]['title'] = !isset($titles_metas['titles_tax_titles'][$taxonomy]['title']) ? '%%_category_title%% %%sep%% %%sitetitle%%' : $titles_metas['titles_tax_titles'][$taxonomy]['title'];
				$titles_metas['titles_tax_titles'][$taxonomy]['description'] = !isset($titles_metas['titles_tax_titles'][$taxonomy]['description']) ? '%%_category_description%%' : $titles_metas['titles_tax_titles'][$taxonomy]['description'];	
			}
		}

		$titles_metas['titles_archives_author_title'] = !isset($titles_metas['titles_archives_author_title']) ? '%%post_author%% %%sep%% %%sitetitle%%' : $titles_metas['titles_archives_author_title'];
		$titles_metas['titles_archives_author_noindex'] = !isset($titles_metas['titles_archives_author_noindex']) ? true : '';
		$titles_metas['titles_archives_date_title'] = !isset($titles_metas['titles_archives_date_title']) ? '%%archive_date%% %%sep%% %%sitetitle%%' : '';
		$titles_metas['titles_archives_date_noindex'] = !isset($titles_metas['titles_archives_date_noindex']) ? true : '';
		$titles_metas['titles_archives_search_title_noindex'] = !isset($titles_metas['titles_archives_search_title_noindex']) ? true : '';
		$titles_metas['titles_nositelinkssearchbox'] = !isset($titles_metas['titles_nositelinkssearchbox']) ? true : '';
		$titles_metas['titles_archives_search_title'] = !isset($titles_metas['titles_archives_search_title']) ? '%%search_keywords%% %%sep%% %%sitetitle%%' : '';
		$titles_metas['titles_archives_404_title'] = !isset($titles_metas['titles_archives_404_title']) ? '404 - Page not found %%sep%% %%sitetitle%%' : $titles_metas['titles_archives_404_title'];

		// Social	
		$social_settings['social_twitter_card'] = true;
		$social_settings['social_facebook_og'] = true;

		// Sitemap
		$sitemap_settings['xml_sitemap_general_enable'] = true;
		$sitemap_settings['xml_sitemap_post_types_list']['post']['include'] = true;
		$sitemap_settings['xml_sitemap_post_types_list']['page']['include'] = true;
		$sitemap_settings['xml_sitemap_taxonomies_list']['category']['include'] = true;
		$sitemap_settings['xml_sitemap_img_enable'] = true; 

		// Advanced
		$advanced_settings['advanced_attachments'] = true;
		$advanced_settings['appearance_universal_metabox'] = true;

		update_option('siteseo_toggle', $toggle_settings);
		update_option('siteseo_titles_option_name', $titles_metas);
		update_option('siteseo_social_option_name', $social_settings);
		update_option('siteseo_xml_sitemap_option_name', $sitemap_settings);
		update_option('siteseo_advanced_option_name', $advanced_settings);

	}

}
settings.php000064400000313541151526414160007131 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}


class Settings{

	static function base(){
		global $speedycache;

		if(!file_exists(SPEEDYCACHE_CACHE_DIR) || !is_writable(WP_CONTENT_DIR)){
			echo '<div class="notice notice-error">
				<p><strong>Error:</strong> '.esc_html__('SpeedyCache was not able to create the cache directory, there might be a permission issue with the '.(defined('SITEPAD') ? 'sitepad-data' : 'wp-content').' directory.', 'speedycache').'</p>
			</div>';
		}
		
		echo '<div id="speedycache-admin">
			<div id="speedycache-navigation">
				<div class="speedycache-logo">
					<img src="'.esc_url(SPEEDYCACHE_URL . '/assets/images/speedycache.png').'" alt="SpeedyCache Logo" width="200" height="35">
					<span>version '.esc_html(SPEEDYCACHE_VERSION).'</span>
				</div>
				<ul>
					<li><a href="#"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/dashboard.svg"/>Dashboard</a></li>
					<li><a href="#cache"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/cache.svg"/>Cache</a></li>
					<li><a href="#file"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/file.svg"/>File Optimization</a></li>
					<li><a href="#excludes"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/excludes.svg"/>Excludes</a></li>
					<li><a href="#preload"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/preload.svg"/>Preloading</a></li>
					<li><a href="#media"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/media.svg"/>Media</a></li>
					<li><a href="#cdn"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/cdn.svg"/>CDN</a></li>';
					
					if(!defined('SITEPAD')){
						echo '<li><a href="#object"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/object.svg"/>Object Cache</a></li>';
					}
					
					echo' <li><a href="#image"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/image.svg"/>Image Optimization</a></li>';
					
					if(!defined('SITEPAD')){
						echo '<li><a href="#bloat"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/broom.svg"/>Bloat</a></li>';
					}
					
					echo' <li><a href="#db"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/db.svg"/>Database</a></li>
					<li><a href="#settings"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/settings.svg"/>Settings</a></li>';

					if(!defined('SITEPAD') && defined('SPEEDYCACHE_PRO')){
						echo '<li><a href="#license"><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/license.svg"/> License</a></li>';
					}

				echo '<ul>
			</div>
			<div class="speedycache-tabs">
				<div class="speedycache-tab" id="speedycache-dashboard">';
					self::dashboard_tab();
				echo '</div>
			
				<div class="speedycache-tab" id="speedycache-cache">';
					self::cache_tab();
				echo '</div>
				<div class="speedycache-tab" id="speedycache-file">';
					self::file_tab();
				echo '</div>
				
				<div class="speedycache-tab" id="speedycache-preload">';
					self::preload_tab();
				echo '</div>
				<div class="speedycache-tab" id="speedycache-media">';
					self::media_tab();
				echo '</div>
				<div class="speedycache-tab" id="speedycache-excludes">';
					self::excludes_tab();
				echo '</div>
				
				<div class="speedycache-tab" id="speedycache-cdn">';
					self::cdn_tab();
				echo '</div>
				
				<div class="speedycache-tab" id="speedycache-image">';
					do_action('speedycache_image_optm_tmpl');
					if(!defined('SPEEDYCACHE_PRO') || (defined('SPEEDYCACHE_PRO_VERSION') && version_compare(SPEEDYCACHE_PRO_VERSION, '1.2.0', '<'))){
						self::pro_notice('Image Optimization');
					}
				echo '</div>
				
				<div class="speedycache-tab" id="speedycache-object">';
					do_action('speedycache_object_cache_tmpl');
					if(!defined('SPEEDYCACHE_PRO') || (defined('SPEEDYCACHE_PRO_VERSION') && version_compare(SPEEDYCACHE_PRO_VERSION, '1.2.0', '<'))){
						self::pro_notice('Object Cache');
					}
				echo '</div>

				<div class="speedycache-tab" id="speedycache-bloat">';
					do_action('speedycache_bloat_tmpl');
					if(!defined('SPEEDYCACHE_PRO') || (defined('SPEEDYCACHE_PRO_VERSION') && version_compare(SPEEDYCACHE_PRO_VERSION, '1.2.0', '<'))){
						self::pro_notice('Bloat Settings');
					}
				echo '</div>
				
				<div class="speedycache-tab" id="speedycache-db">';
					do_action('speedycache_db_tmpl');
					if(!defined('SPEEDYCACHE_PRO') || (defined('SPEEDYCACHE_PRO_VERSION') && version_compare(SPEEDYCACHE_PRO_VERSION, '1.2.0', '<'))){
						self::pro_notice('DB Optimization');
					}
				echo '</div>

				<div class="speedycache-tab" id="speedycache-settings">';
					self::settings_tab();
				echo '</div>';
				
				if(!defined('SITEPAD')) {
					do_action('speedycache_license_tmpl');
				}
	
			echo '</div>';
			
			if(!defined('SITEPAD')) {
				echo '<div class="speedycache-sidebar">
					<div class="speedycache-need-help">
					<p>Quick Access</p>
					<div class="speedycache-quick-links">
						<div class="speedycache-quick-access-item">
							<span class="dashicons dashicons-format-status"></span>
							<a href="https://softaculous.deskuss.com/open.php?topicId=19" target="_blank">Support</a>
						</div>
						<div class="speedycache-quick-access-item">
							<span class="dashicons dashicons-media-document"></span>
							<a href="https://speedycache.com/docs/" target="_blank">Documentation</a>
						</div>
						<div class="speedycache-quick-access-item">
							<span class="dashicons dashicons-feedback"></span>
							<a href="https://softaculous.deskuss.com/open.php?topicId=19" target="_blank">Feedback</a>
						</div>
						<div class="speedycache-quick-access-item">
							<span class="dashicons dashicons-star-filled"></span><a href="https://wordpress.org/support/plugin/speedycache/reviews/?rate=5#new-post" target="_blank">Rate Us</a>
						</div>
					</div>
				</div>';
				
				if(!defined('SPEEDYCACHE_PRO')){
					self::pro_upsell();
				}
				
				echo '</div>';
			}
		echo '</div>';
		
	}
	
	static function dashboard_tab(){
		global $speedycache;
		
		$speed_results = get_option('speedycache_pagespeed_test', []);
		
		$speed_score = 0;
		$speed_colors = ['#0c6', '#00cc663b', '#080'];
		if(!empty($speed_results)){
			$speed_colors = Util::pagespeed_color($speed_results['score']);
			$speed_score = $speed_results['score'];
		}
		
		
		$speedycache->object_memory = 'None';	
		if(!empty($speedycache->object['enable']) && class_exists('Redis') && class_exists('\SpeedyCache\ObjectCache')){
			try{
				$speedycache->object_memory = \SpeedyCache\ObjectCache::get_memory();
			} catch(\Exception $e) {
				$memory = 'None';
			}
		}
		
		$license_expires = '';
		if(defined('SPEEDYCACHE_PRO') && !empty($speedycache->license['expires'])){
			$license_expires = $speedycache->license['expires'];
			$license_expires = substr($license_expires, 0, 4).'/'.substr($license_expires, 4, 2).'/'.substr($license_expires, 6);
		}
		
		
		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/dashboard.svg" height="32" width="32"/> Dashboard</h2>
			<div class="speedycache-admin-row">
				<div class="speedycache-perf-score speedycache-is-block">
					<div class="speedycache-perf-score-meter-heading">
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="24" height="24"><path d="M349.4 44.6c5.9-13.7 1.5-29.7-10.6-38.5s-28.6-8-39.9 1.8l-256 224c-10 8.8-13.6 22.9-8.9 35.3S50.7 288 64 288H175.5L98.6 467.4c-5.9 13.7-1.5 29.7 10.6 38.5s28.6 8 39.9-1.8l256-224c10-8.8 13.6-22.9 8.9-35.3s-16.6-20.7-30-20.7H272.5L349.4 44.6z"/></svg>
						<h4>Performance Score <span id="speedycache-analyze">[Analyze]<span class="speedycache-spinner"></span></span></h4>
					</div>
					<div class="speedycache-perf-score-meter">
						<div class="speedycache-perf-score-donut">
							<svg width="80%" height="80%" viewBox="0 0 40 40">
								<circle cx="20" cy="20" r="15.91549430918954" fill="'.esc_attr($speed_colors[1]).'"></circle>
								<circle cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="2" stroke-linecap="round" stroke-dasharray="'.esc_html($speed_score).' '.esc_html(100 - $speed_score).'" stroke-dashoffset="25" style="stroke:'.esc_attr($speed_colors[0]).';"></circle>
								<g class="speedycache-donut-text speedycache-donut-text-1">
									<text y="56%" transform="translate(0, 2)">
										<tspan x="50%" text-anchor="middle" style="fill:'.esc_attr($speed_colors[2]).'">'.esc_html($speed_score).'</tspan> 
									</text>
								</g>
							</svg>
						</div>
						<div class="speedycache-perf-score-guide">
							<div>
								<span style="background-color:#f33;"></span>
								0-49
							</div>
							<div>
								<span style="background-color:#fa3;"></span>
								50-89
							</div>
							<div>
								<span style="background-color:#0c6;"></span>
								90-100
							</div>
						
						</div>
					</div>
				</div>
				<div class="speedycache-dashboard-info">';
				if(!defined('SITEPAD')){
					echo'
					<div class="speedycache-licence-brief speedycache-is-block">
						<h4>License</h4>
						<span>Version: '.esc_html(SPEEDYCACHE_VERSION).'</span>
						<span>Status: '.(!defined('SPEEDYCACHE_PRO') ? 'Free' : (!empty($speedycache->license) && defined('SPEEDYCACHE_PRO') ? 'Pro' : 'License not Linked')).'</span>
						<span>Expires on: '.(!defined('SPEEDYCACHE_PRO') ? 'Never' : (!empty($speedycache->license) && !empty($license_expires) ?  esc_html($license_expires) : '')).'</span>
					</div>';
				}
				echo'
				<div class="speedycache-is-block">
					<h4>Cache Info</h4>
					<span>File Cache: '.(!empty($speedycache->options['status']) ? esc_html__('Enabled', 'speedycache') : esc_html__('Disabled', 'speedycache')).'</span>';
					if(!defined('SITEPAD')){
						echo'<span>Object Cache: '.(!empty($speedycache->object['enable']) ? esc_html__('Enabled', 'speedycache') : esc_html__('Disabled', 'speedycache')).'</span>';
					}
					echo'
					<span>CDN: '.(!empty($speedycache->cdn) && !empty($speedycache->cdn['cdn_type']) ? esc_html(ucfirst($speedycache->cdn['cdn_type'])) : 'OFF').'</span>
				</div>
				</div>
			</div>';
			
			// TODO: Need to add this stats code in the Pro version.
			if(defined('SPEEDYCACHE_PRO')){
				do_action('speedycache_pro_stats_tmpl');
			}

			echo '<h3>Manage Cache</h3>
			<form method="POST" action="'.esc_url(admin_url('admin-post.php')).'">';
				wp_nonce_field('speedycache_post_nonce');
			
				echo '<input type="hidden" value="speedycache_delete_cache" name="action"/>
				<div class="speedycache-option-wrap">
					<label for="speedycache_delete_minified" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_delete_minified" name="minified"/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Delete Minified', 'speedycache').'</span>
						<span class="speedycache-option-desc">'.esc_html__('Deletes Minfied/ Combined CSS/JS files', 'speedycache').'</span>
					</div>
				</div>';

				if(defined('SPEEDYCACHE_PRO')){
					echo '<div class="speedycache-option-wrap">
						<label for="speedycache_delete_fonts" class="speedycache-custom-checkbox">
							<input type="checkbox" id="speedycache_delete_fonts" name="fonts"/>
							<div class="speedycache-input-slider"></div>
						</label>
						<div class="speedycache-option-info">
							<span class="speedycache-option-name">'.esc_html__('Delete Fonts', 'speedycache').'</span>
							<span class="speedycache-option-desc">'.esc_html__('Deletes Local Google Fonts', 'speedycache').'</span>
						</div>
					</div>';
				}
				
				echo '<div class="speedycache-option-wrap">
					<label for="speedycache_delete_gravatars" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_delete_gravatars" name="gravatars"/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Delete Gravatars', 'speedycache').'</span>
						<span class="speedycache-option-desc">'.esc_html__('Delete locally hosted Gravatars.', 'speedycache').'</span>
					</div>
				</div>
				<div class="speedycache-option-wrap">
					<label for="speedycache_preload_cache" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_preload_cache" name="preload_cache"/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Preload Cache', 'speedycache').'</span>
						<span class="speedycache-option-desc">'.esc_html__('After cache gets deleted, it restarts auto cache generation.', 'speedycache').'</span>
					</div>
				</div>	
				<div class="speedycache-option-wrap">
					<div class="submit">
						<input type="submit" value="'.esc_html__('Clear all cache and the selections', 'speedycache').'" class="speedycache-button speedycache-btn-black"/>
					</div>
				</div>
			</form>';
			
			if(defined('SPEEDYCACHE_PRO')){
				do_action('speedycache_pro_logs_tmpl');
			}
	}
	
	static function cache_tab(){
		global $speedycache;

		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/cache.svg" height="32" width="32"/> Cache Settings</h2>
		<form method="post">';
		wp_nonce_field('speedycache_ajax_nonce');
		echo '<input type="hidden" value="speedycache_save_cache_settings" name="action"/>
		<div class="speedycache-option-wrap">
			<label for="speedycache_enable_cache" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['status']) ? ' checked' : '').' id="speedycache_enable_cache" name="status"/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Enable Cache', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Enables caching', 'speedycache').'</span> 
			</div>
		</div>
		
		<div class="speedycache-option-wrap">
			<label for="speedycache_mobile" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['mobile']) ? ' checked' : '').' id="speedycache_mobile" name="mobile"/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Mobile Override', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Disable desktop cache display on mobile devices.', 'speedycache').'</span>
			</div>
		</div>';

		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_mobile_theme" class="speedycache-custom-checkbox">
					<input type="checkbox" '.(!empty($speedycache->options['mobile_theme']) ? ' checked' : '').' id="speedycache_mobile_theme" name="mobile_theme"/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Mobile Cache', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Separate cache for Mobile version of your website, modern themes don\'t require this', 'speedycache').'</span>
				</div>
			</div>';

		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label for="speedycache_mobile_theme" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_mobile_theme" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Mobile Cache', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Separate cache for Mobile version of your website, modern themes don\'t require this', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		echo '<div class="speedycache-option-wrap">
			<label for="speedycache_preload" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['preload']) ? ' checked' : '').' id="speedycache_preload" name="preload"/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Preload', 'speedycache').'
				<span class="speedycache-modal-settings-link" setting-id="speedycache_preload" style="display:'.(!empty($speedycache->options['preload']) ? 'inline-block' : 'none').';">- Settings</span></span>
				<span class="speedycache-option-desc">'.esc_html__('Create the cache of all the site automatically', 'speedycache').'</span>
			</div>
		</div>
		<!--SpeedyCache Update Post Modal Starts Here-->
		<div modal-id="speedycache_preload" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Preload Settings', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content">
					<p style="color:#666;margin-top:0 !important;">'.esc_html__('Select the interval after which you want the preload to run', 'speedycache').'</p>

					<div class="speedycache-form-input">
						<label style="width:100%;">
							<span style="font-weight:500; margin-bottom:5px">'.esc_html__('Select Preload interval', 'speedycache').'</span>
							<select name="preload_interval" value="'.(!empty($speedycache->options['preload_interval']) ? esc_attr($speedycache->options['preload_interval']) : '').'">
								<option value="2" '.(isset($speedycache->options['preload_interval']) ? selected($speedycache->options['preload_interval'], '2', false) : '').'>'.esc_html__('Every 2 hours', 'speedycache').'</option>
								<option value="6" '.(isset($speedycache->options['preload_interval']) ? selected($speedycache->options['preload_interval'], '6', false) : '').'>'.esc_html__('Every 6 hours', 'speedycache').'</option>
								<option value="12" '.(isset($speedycache->options['preload_interval']) ? selected($speedycache->options['preload_interval'], '12', false) : '').'>'.esc_html__('Every 12 hours', 'speedycache').'</option>
								<option value="24" '.(isset($speedycache->options['preload_interval']) ? selected($speedycache->options['preload_interval'], '24', false) : '').'>'.esc_html__('Once a day', 'speedycache').'</option>
								<option value="168" '.(isset($speedycache->options['preload_interval']) ? selected($speedycache->options['preload_interval'], '168', false) : '').'>'.esc_html__('Once a week', 'speedycache').'</option>
							</select>
						</label>
					</div>
				</div>
				<div class="speedycache-modal-footer">
					<button type="button" action="close">
						<span>'.esc_html__('Submit', 'speedycache').'</span>
					</button>
				</div>
			</div>
		</div>
		<div class="speedycache-option-wrap">
			<label for="speedycache_lbc" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_lbc" name="lbc" '.(!empty($speedycache->options['lbc']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Browser Caching', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Stores web data locally for faster loading.', 'speedycache').'</span>
			</div>
		</div>
		
		<div class="speedycache-option-wrap">
			<label for="speedycache_logged_in_user" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['logged_in_user']) ? ' checked' : '').' id="speedycache_logged_in_user" name="logged_in_user"/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Logged-in Users', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Serve cached version to logged in user.', 'speedycache').'</span>
			</div>
		</div>
		
		<div class="speedycache-option-wrap">
			<label for="speedycache_gzip_compression" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['gzip']) ? ' checked' : '').' id="speedycache_gzip_compression" name="gzip"/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('GZIP Compressions', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Compresses the text files to reduce the size to be sent on the network.', 'speedycache').'</span>
			</div>
		</div>

		<div class="speedycache-option-wrap">
			<label for="speedycache_purge_varnish" class="speedycache-custom-checkbox">
				<input type="checkbox" '.(!empty($speedycache->options['purge_varnish']) ? ' checked' : '').' id="speedycache_purge_varnish" name="purge_varnish" />
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Purge Varnish', 'speedycache').'
				<span class="speedycache-modal-settings-link" setting-id="speedycache_purge_varnish" style="display:'.(!empty($speedycache->options['purge_varnish']) ? 'inline-block' : 'none').';">- Settings</span>
				</span>
				<span class="speedycache-option-desc">'.esc_html__('Deletes cache created by Varnish on Deletion of cache from SpeedyCache', 'speedycache').'</span>
			</div>
		</div>
		
		<!--SpeedyCache Update Post Modal Starts Here-->
		<div modal-id="speedycache_purge_varnish" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Varnish Settings', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content">
					<p style="color:#666;margin-top:0 !important;">'.esc_html__('If you use any different IP for Varnish than the default then set it here.', 'speedycache').'</p>

					<div class="speedycache-form-input">
						<label style="width:100%;">
							<span style="font-weight:500; margin-bottom:5px">'.esc_html__('Set your Varnish IP', 'speedycache').'</span>
							<input type="text" name="varniship" style="width:100%;" value="'. (!empty($speedycache->options['varniship']) ? esc_attr($speedycache->options['varniship']) : '127.0.0.1').'"/><br/>
						</label>
					</div>
				</div>
				<div class="speedycache-modal-footer">
					<button type="button" action="close">
						<span>'.esc_html__('Submit', 'speedycache').'</span>
					</button>
				</div>
			</div>
		</div>

		<h3>'.esc_html__('Cache Lifespan', 'speedycache').'</h3>
		<p>'.esc_html__('This defines the time after which the cache will be automatically deleted. Set to 0 to disable automatic cache deletion.', 'speedycache').'</p>
		<input type="number" min="0" name="purge_interval" value="'.(isset($speedycache->options['purge_interval']) ? esc_html($speedycache->options['purge_interval']) : 24).'"/>
		<select name="purge_interval_unit">
			<option value="hours" '.(!empty($speedycache->options['purge_interval_unit']) ? selected($speedycache->options['purge_interval_unit'], 'hours', false) : ' selected').'>'.esc_html__('Hours', 'speedycache').'</option>
			<option value="days" '.(!empty($speedycache->options['purge_interval_unit']) ? selected($speedycache->options['purge_interval_unit'], 'days', false) : '').'>'.esc_html__('Days', 'speedycache').'</option>
		</select>
		<div>
		<input type="checkbox" id="speedycache-run-exact-time" name="purge_enable_exact_time" value="1" '.(!empty($speedycache->options['purge_enable_exact_time']) ? checked($speedycache->options['purge_enable_exact_time'], true, false) : '').'/>'.esc_html__('Run at exact time', 'speedycache').'
		<div id="speedycache-exact-time-selector" style="'.(empty($speedycache->options['purge_enable_exact_time']) ? 'display:none;' : '').'">
			<label>
				<input type="time" name="purge_exact_time" value="'.(!empty($speedycache->options['purge_exact_time']) ? esc_attr($speedycache->options['purge_exact_time']) : '').'"/>'.esc_html__('Select exact time', 'speedycache').'
			</label>
			<p class="description">'.esc_html__('This is dependent on WP Cron, which does not guarantee execution at an exact time. For more details, ', 'speedycache').'<a href="https://speedycache.com/docs/caching/running-cache-lifespan-at-specific-time/" target="_blank">click here</a>
		</div>
		<div>
			<input type="checkbox" name="auto_purge_fonts" value="1" '.(!empty($speedycache->options['auto_purge_fonts']) ? checked($speedycache->options['auto_purge_fonts'], true, false) : '').'/>'.esc_html__('Delete Fonts', 'speedycache').'
			<input type="checkbox" name="auto_purge_gravatar" value="1" '.(!empty($speedycache->options['auto_purge_gravatar']) ? checked($speedycache->options['auto_purge_gravatar'], true, false) : '').'/>'.esc_html__(
			'Delete Gravatar', 'speedycache').'
			<p class="description">'.esc_html__('Deletion of these options only takes effect if the lifespan is more than 10 hours.', 'speedycache').'</p>
		</div>
		
		</div>
		';

		self::save_btn();
		echo '</form>';
	}
	
	static function file_tab(){
		global $speedycache;

		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/file.svg" height="32" width="32"/> File Optimization</h2>
		<form method="post">';
		wp_nonce_field('speedycache_ajax_nonce');
		echo '<input type="hidden" name="action" value="speedycache_save_file_settings"/>';
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_minify_html" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_minify_html" name="minify_html" '.(!empty($speedycache->options['minify_html']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Minify HTML', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Removes comments, extra spaces', 'speedycache').'</span>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Minify HTML', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Removes comments, extra spaces', 'speedycache').'</span>
				</div>
			</div>';
		}

		echo '<div class="speedycache-option-wrap">
			<label for="speedycache_minify_css" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_minify_css" name="minify_css" '.(!empty($speedycache->options['minify_css']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Minify CSS', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('You can decrease the size of CSS files', 'speedycache').'</span>
			</div>
		</div>
		
		<div class="speedycache-option-wrap">
			<label for="speedycache_combine_css" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_combine_css" name="combine_css" '.(!empty($speedycache->options['combine_css']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Combine CSS', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Combines CSS files to reduce HTTP requests', 'speedycache').'</span>
			</div>
		</div>';
		
		// Critical CSS Option
		if(!defined('SITEPAD')){
			if(defined('SPEEDYCACHE_PRO') && !empty($speedycache->license) && !empty($speedycache->license['active'])){
				echo '<div class="speedycache-option-wrap">
					<label for="speedycache_critical_css" class="speedycache-custom-checkbox" style="margin-top:0;">
						<input type="checkbox" id="speedycache_critical_css" name="critical_css" '.(!empty($speedycache->options['critical_css']) ? ' checked' : '').'/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Critical CSS', 'speedycache');
						
						if(!empty($speedycache->options['critical_css'])){
							echo ' - 
							<span class="speedycache-action-link" action-name="speedycache_critical_css">'.esc_html__('Create Now', 'speedycache').'</span>
							&nbsp;&nbsp;|&nbsp;&nbsp;
							<span class="speedycache-modal-settings-link" setting-id="speedycache_critical_css">'.esc_html__('Logs', 'speedycache').'</span>';
						}
						echo '</span><span class="speedycache-option-desc">'.esc_html__('It extracts the necessary CSS of the viewport on load to improve load speed.', 'speedycache').'</span>
					</div>
				</div>';
				
				echo wp_kses(\SpeedyCache\CriticalCss::status_modal(), array_merge(wp_kses_allowed_html('post'), [
					'div' => [
						'modal-id' => true,
						'class' => true,
						'title' => true,
						'style' => true,
					]
				]));
			} else { 
				if(empty($speedycache->license) || empty($speedycache->license['active'])){
					$need_key = true;
				}
				
				echo '<div class="speedycache-option-wrap speedycache-disabled">
					<label class="speedycache-custom-checkbox">
						<input type="checkbox" disabled/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Critical CSS', 'speedycache').' <span class="speedycache-premium-tag">'.(!empty($need_key) ? 'Link License Key' : 'Premium').'</span></span>
						<span class="speedycache-option-desc">'.esc_html__('It extracts the necessary CSS of the viewport on load to improve load speed.', 'speedycache').'</span>
					</div>
				</div>';
			}
		}
		
		// Unused CSS
		if(!defined('SITEPAD')){
			if(defined('SPEEDYCACHE_PRO') && !empty($speedycache->license) && !empty($speedycache->license['active'])){
				echo '<div class="speedycache-option-wrap">
					<label for="speedycache_unused_css" class="speedycache-custom-checkbox" style="margin-top:0;">
						<input type="checkbox" id="speedycache_unused_css" name="unused_css" '.(!empty($speedycache->options['unused_css']) ? ' checked' : '').'/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name" title="Unused CSS"><span>'.esc_html__('Unused CSS', 'speedycache').'</span><a href="https://speedycache.com/docs/file-optimization/how-to-remove-unused-css/" target="_blank"><span class="dashicons dashicons-info" style="font-size:14px"></span></a>
						<span class="speedycache-modal-settings-link" setting-id="speedycache_unused_css" style="display:'.(!empty($speedycache->options['unused_css']) ? 'inline-block' : 'none').';">- Settings</span>
						</span><span class="speedycache-option-desc">'.esc_html__('It removes the unused CSS.', 'speedycache').'</span>
					</div>
				</div>

				<div modal-id="speedycache_unused_css" class="speedycache-modal">
					<div class="speedycache-modal-wrap">
						<div class="speedycache-modal-header">
							<div>'.esc_html__('Unused CSS Settings', 'speedycache').'</div>
							<div title="Close Modal" class="speedycache-close-modal">
								<span class="dashicons dashicons-no"></span>
							</div>
						</div>
						<div class="speedycache-modal-content speedycache-info-modal">
							<p>'.esc_html__('Extracts the CSS being used on the page.', 'speedycache').'</p>
							<div>
								<label>
									<span style="font-weight:500; margin:20px 0 3px 0; display:block;">'.esc_html__('Load Unused CSS', 'speedycache').'</span>
									<span class="speedycache-model-label-description" style="margin-bottom:5px;">'.esc_html__('Select the way you want the Unused CSS to load.', 'speedycache').'</span>
								</label>
								<input type="radio" id="speedycache_unusedcss_async" name="unusedcss_load" value="async" '.(empty($speedycache->options['unusedcss_load']) || (!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] == 'async') ? 'checked' : '').'/>
								<input type="radio" id="speedycache_unusedcss_interaction" name="unusedcss_load" value="interaction" '.(!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] == 'interaction' ? 'checked' : '').'/>
								<input type="radio" id="speedycache_unusedcss_remove" name="unusedcss_load" value="remove" '.(!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] == 'remove' ? 'checked' : '').'/>
								<div class="speedycache-radio-input">
									<label for="speedycache_unusedcss_async">'.esc_html__('Asynchronously', 'speedycache').'</label>
									<label for="speedycache_unusedcss_interaction">'.esc_html__('On User Interaction', 'speedycache').'</label>
									<label for="speedycache_unusedcss_remove">'.esc_html__('Remove', 'speedycache').'</label>
								</div>
							</div>
							<div class="speedycache-unusedcss-excludes">
								<label for="speedycache_unused_css_exclude_stylesheets" style="width:100%;">
									<span style="font-weight:500; margin:20px 0 3px 0; display:block;">'.esc_html__('Exclude Stylesheets', 'speedycache').'</span>
									<span class="speedycache-model-label-description">'.esc_html__('Enter the URL, name or the stylesheet to be excluded from removing unused CSS.', 'speedycache').'</span>
									<textarea name="unused_css_exclude_stylesheets" id="speedycache_unused_css_exclude_stylesheets" rows="4" placeholder="Enter URL, CSS file name one per line">'.(!empty($speedycache->options['unused_css_exclude_stylesheets']) ? esc_html(implode("\n", $speedycache->options['unused_css_exclude_stylesheets'])) : '').'</textarea>
								</label>
								<br><br>
								<label for="speedycache_unusedcss_include_selector" style="width:100%;">
									<span style="font-weight:500; margin:20px 0 3px 0; dispaly:block;">'.esc_html__('Include Selectors', 'speedycache').'</span>
									<span class="speedycache-model-label-description">'.esc_html__('Enter Selectors you want to be included in used CSS', 'speedycache').'</span>
									<textarea name="unusedcss_include_selector" id="speedycache_unusedcss_include_selector" rows="4" placeholder="Enter selector one per line">'.(!empty($speedycache->options['unusedcss_include_selector']) ? esc_html(implode("\n", $speedycache->options['unusedcss_include_selector'])) : '').'</textarea>
								</label>
							</div>
							<div class="speedycache-modal-footer">
								<button type="button" action="close">
									<span>'.esc_html__('Submit', 'speedycache').'</span>
								</button>
							</div>
						</div>
					</div>
				</div>';
			} else {
				echo '<div class="speedycache-option-wrap speedycache-disabled">
					<label class="speedycache-custom-checkbox">
						<input type="checkbox" disabled/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'.esc_html__('Unused CSS', 'speedycache').'<span class="speedycache-premium-tag">'.(!empty($need_key) ? 'Link License Key' : 'Premium').'</span></span>
						<span class="speedycache-option-desc">'.esc_html__('It removes the unused CSS from the page.', 'speedycache').'</span>
					</div>
				</div>';
			}
		}
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_minify_js" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_minify_js" name="minify_js" '.(!empty($speedycache->options['minify_js']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Minify JS', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('You can decrease the size of JS files', 'speedycache').'</span>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<div class="speedycache-form-input">
					<label class="speedycache-custom-checkbox">
						<input type="checkbox"disabled/>
						<div class="speedycache-input-slider"></div>
					</label>
				</div>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Minify JS', 'speedycache').'<span class="speedycache-premium-tag">Premium</span></span>
					<span class="speedycache-option-desc">'.esc_html__('You can decrease the size of JS files', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		echo '<div class="speedycache-option-wrap">
			<label for="speedycache_combine_js" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_combine_js" name="combine_js" '.(!empty($speedycache->options['combine_js']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Combine JS', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Reduce HTTP requests by Combining JS files', 'speedycache').'</span>
			</div>
		</div>';

		// Delay JS option
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_delay_js" class="speedycache-custom-checkbox" style="margin-top:0;">
					<input type="checkbox" id="speedycache_delay_js" name="delay_js" '.(!empty($speedycache->options['delay_js']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name"><span>'.esc_html__('Delay JS', 'speedycache').'</span><a href="https://speedycache.com/docs/file-optimization/how-to-delay-js-until-user-interaction/" target="_blank"><span class="dashicons dashicons-info" style="font-size:14px"></span></a>
					<span class="speedycache-modal-settings-link" setting-id="speedycache_delay_js" style="display:'.(!empty($speedycache->options['delay_js']) ? 'inline-block' : 'none').';">- Settings</span>
					</span><span class="speedycache-option-desc">'.esc_html__('Delays JS until user interaction(like scroll, click etc) to improve performance', 'speedycache').'</span>
				</div>
			</div>
			
			<div modal-id="speedycache_delay_js" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
						<div>'.esc_html__('Delay JS', 'speedycache').'</div>
						<div title="Close Modal" class="speedycache-close-modal">
							<span class="dashicons dashicons-no"></span>
						</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<p>'.esc_html__('Delay All is a more aggressive option which can increase the chances of breaking the site too.', 'speedycache').'</p>
						<input type="radio" id="speedycache_delayjs_selected" name="delay_js_mode" value="selected" '.(empty($speedycache->options['delay_js_mode']) || (!empty($speedycache->options['delay_js_mode']) && $speedycache->options['delay_js_mode'] == 'selected') ? 'checked' : '').'/>
						<input type="radio" id="speedycache_delayjs_all" name="delay_js_mode" value="all" '.(!empty($speedycache->options['delay_js_mode']) && $speedycache->options['delay_js_mode'] == 'all' ? 'checked' : '').'/>
						
						<div class="speedycache-radio-input">
							<label for="speedycache_delayjs_selected">'.esc_html__('Delay Selected', 'speedycache').'</label>
							<label for="speedycache_delayjs_all">'.esc_html__('Delay All', 'speedycache').'</label>
						</div>
						<div class="speedycache-delay_js_list">
							<label for="speedycache_delay_js_excludes" style="width:100%;">
								<span style="font-weight:500; margin:20px 0 3px 0; display:block;">Scripts to exclude</span>
								<span style="display:block; font-weight:400; font-size:12px; color: #2c2a2a;">Enter Below The Scipts that you no not want to be delayed.</span>
								<textarea name="delay_js_excludes" id="speedycache_delay_js_excludes" rows="4" placeholder="jquery.min">'.(!empty($speedycache->options['delay_js_excludes']) && is_array($speedycache->options['delay_js_excludes']) ? esc_html(implode("\n", $speedycache->options['delay_js_excludes'])) : '').'</textarea>
							</label>
			
							<label for="speedycache_delay_js_scripts" style="width:100%;">
								<span style="font-weight:500; margin:20px 0 3px 0; dispaly:block;">Scripts to Delay</span>
								<span style="display:block; font-weight:400; font-size:12px; color: #2c2a2a;">Enter the scripts that you want to be delayed like googletagmanager.com</span>
								<textarea name="delay_js_scripts" id="speedycache_delay_js_scripts" rows="4" placeholder="googletagmanager.com">'.(!empty($speedycache->options['delay_js_scripts']) && is_array($speedycache->options['delay_js_scripts']) ? esc_html(implode("\n", $speedycache->options['delay_js_scripts'])) : '').'</textarea>
								<h5>Suggestions</h5>
								<p style="position: relative;">
								<button class="speedycache-delay-suggestions">
								<span>Use These</span>
								<svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 -960 960 960" width="18px" fill="#e3e3e3"><path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"/></svg>
								</button>
								<span class="speedycache-modal-scripts">
									fbevents.js<br>
									google-analytics.com<br>
									adsbygoogle.js<br>
									googletagmanager.com<br>
									fbq(<br>
									ga( \' <br>
									ga(\'<br>
									/gtm.js<br>
									/gtag/js<br>
									gtag(<br>
									/gtm-<br>
									/gtm.<br>
								</span>
								</p>
							</label>
						</div>
						<div class="speedycache-modal-footer">
							<button type="button" action="close">
								<span>'.esc_html__('Submit', 'speedycache').'</span>
							</button>
						</div>
					</div>
				</div>
			</div>';
		}else{
		echo '<div class="speedycache-option-wrap speedycache-disabled">
			<label class="speedycache-custom-checkbox" style="margin-top:0;">
				<input type="checkbox" disabled/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Delay JS', 'speedycache').'<span class="speedycache-premium-tag">Premium</span></span>
				</span><span class="speedycache-option-desc">'.esc_html__('Delays JS until user interaction(like scroll, click etc) to improve performance', 'speedycache').'</span>
			</div>
		</div>';
		}
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_render_blocking" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_render_blocking" name="render_blocking" '.(!empty($speedycache->options['render_blocking']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name" setting-id="speedycache_render_blocking">'.esc_html__('Defer JS', 'speedycache').'
					<span class="speedycache-modal-settings-link" setting-id="speedycache_render_blocking" style="display:'.(!empty($speedycache->options['render_blocking']) ? 'inline-block' : 'none').';">- Settings</span>
					</span><span class="speedycache-option-desc">'.esc_html__('Defers render-blocking JavaScript resources', 'speedycache').'</span>
				</div>
			</div>

			<div modal-id="speedycache_render_blocking" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Defer JS', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content speedycache-info-modal">
					
					<div>
						<label for="speedycache_render_blocking_excludes" style="width:100%;">
							<span style="font-weight:500; margin:20px 0 3px 0; display:block;">'.esc_html__('Exclude script from Render Blocking JS', 'speedycache').'</span>
							<span style="display:block; font-weight:400; font-size:12px; color: #2c2a2a;">'.esc_html__('Add one script per line ,Enter the script URL or script ID', 'speedycache').'</span>
							<textarea name="render_blocking_excludes" id="speedycache_render_blocking_excludes" rows="4" style="width:100%">'.(!empty($speedycache->options['render_blocking_excludes']) && is_array($speedycache->options['render_blocking_excludes']) ? esc_html(implode("\n", $speedycache->options['render_blocking_excludes'])) : '').'</textarea>
						</label>
					</div>
					<div class="speedycache-modal-footer">
						<button type="button" action="close">
							<span>'.esc_html__('Submit', 'speedycache').'</span>
						</button>
					</div>
				</div>
			</div>
		</div>';
			

		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
					<label class="speedycache-custom-checkbox">
						<input type="checkbox" disabled/>
						<div class="speedycache-input-slider"></div>
					</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Defer JS', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Defers render-blocking JavaScript resources', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		echo '<div class="speedycache-option-wrap">
			<label for="speedycache_disable_emojis" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_disable_emojis" name="disable_emojis" '. (!empty($speedycache->options['disable_emojis']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Disable Emojis', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('You can remove the emoji inline css and wp-emoji-release.min.js', 'speedycache').'</span>
			</div>
		</div>';
		
		// Lazy Render HTML element
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
					<label for="speedycache_lazy_load_html" class="speedycache-custom-checkbox" style="margin-top:0;">
					<input type="checkbox" id="speedycache_lazy_load_html" name="lazy_load_html" '.(!empty($speedycache->options['lazy_load_html']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name"><span>'.esc_html__('Lazy Render HTML Element', 'speedycache').'</span><a href="https://speedycache.com/docs/file-optimization/how-to-lazy-render-html-elements/" target="_blank"><span class="dashicons dashicons-info" style="font-size:14px"></span></a>
					<span class="speedycache-modal-settings-link" setting-id="speedycache_lazy_load_html" style="display:'.(!empty($speedycache->options['lazy_load_html']) ? 'inline-block' : 'none').';">- Settings</span>
					</span><span class="speedycache-option-desc">'.esc_html__('Lazy Render a HTML element(class or id) if not in view-port.', 'speedycache').'</span>
				</div>
			</div>
			<div modal-id="speedycache_lazy_load_html" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
						<div>'.esc_html__('Lazy Render HTML Elements', 'speedycache').'</div>
						<div title="Close Modal" class="speedycache-close-modal">
							<span class="dashicons dashicons-no"></span>
						</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<p>'.esc_html__('Lazy Rendering HTML is usually good for Comments.', 'speedycache').'</p>
						<div>
							<label for="speedycache_lazy_load_html_elements" style="width:100%;">
								<span style="font-weight:500; margin:20px 0 3px 0; display:block;">'.esc_html__('Elements to Lazy Render', 'speedycache').'</span>
								<span style="display:block; font-weight:400; font-size:12px; color: #2c2a2a;">'.esc_html__('Add one element per line, use # as prefix for ID and . as prefix for class.', 'speedycache').'</span>
								<textarea name="lazy_load_html_elements"id="lazy_load_html_elements" rows="4" style="width:100%">'.(!empty($speedycache->options['lazy_load_html_elements']) ? esc_html(implode("\n", $speedycache->options['lazy_load_html_elements'])) : '').'</textarea>
							</label>
						</div>
						<div class="speedycache-modal-footer">
							<button type="button" action="close">
								<span>'.esc_html__('Submit', 'speedycache').'</span>
							</button>
						</div>
					</div>
				</div>
			</div>';
		}else{
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label for="speedycache_lazy_load_html" class="speedycache-custom-checkbox" style="margin-top:0;">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Lazy Render HTML Element', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					</span><span class="speedycache-option-desc">'.esc_html__('Lazy Render a HTML element(class or id) if not in view-port.', 'speedycache').'</span>
				</div>
			</div>';
		}

		self::save_btn();
		echo '</form>';
		
	}

	static function preload_tab(){
		global $speedycache;
		
		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/preload.svg" height="32" width="32"/> Preload Settings</h2>
		<form method="post">';
		wp_nonce_field('speedycache_ajax_nonce');
		echo '<input type="hidden" value="speedycache_save_preload_settings" name="action"/>';
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_critical_images" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_critical_images" name="critical_images" '.(!empty($speedycache->options['critical_images']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Preload Critical Images', 'speedycache').'
					<span class="speedycache-modal-settings-link" setting-id="speedycache_critical_images" style="display:'.(!empty($speedycache->options['critical_images']) ? 'inline-block' : 'none').';">- Settings</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Preloads critical Images to improve LCP', 'speedycache').'</span>
				</div>
			</div>

			<!--SpeedyCache Lazy Load Modal Starts here-->
			<div modal-id="speedycache_critical_images" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
						<div>'.esc_html__('Preload Critical Images', 'speedycache').'</div>
						<div title="Close Modal" class="speedycache-close-modal">
							<span class="dashicons dashicons-no"></span>
						</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<div class="speedycache-modal-block">
							<p>'.esc_html__('Select the number of images you want to be preloaded.', 'speedycache').'</p>
							<table>
							<tr>
								<th>'.esc_html__('Critical Image Count', 'speedycache').'</th>
								<td>
									<div class="speedycache-form-input">
										<select name="critical_image_count" value="'.(!isset($speedycache->options['critical_image_count']) ? '' : esc_attr($speedycache->options['critical_image_count'])).'">';
											$image_count = array('1','2','3','4','5');

											foreach($image_count as $count){
												echo '<option value="'.esc_attr($count).'" '. ((!empty($speedycache->options['critical_image_count']) && $speedycache->options['critical_image_count'] == $count ) ? ' selected' : '') .'>'.esc_html($count).'</option>';
											}

										echo '</select>
									</div>
								</td>
							</tr>
							</table>
						</div>
					</div>
					<div class="speedycache-modal-footer">
						<button type="button" action="close">
							<span>'.esc_html__('Submit', 'speedycache').'</span>
						</button>
					</div>
				</div>
			</div>';

		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Preload Critical Images', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Preloads critical Images to improve LCP', 'speedycache').'</span>
				</div>				
			</div>';
		}

		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_instant_page" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_instant_page" name="instant_page" '.(!empty($speedycache->options['instant_page']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Instant Page', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Improves page load speed', 'speedycache').'</span>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Instant Page', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Improves page load speed', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		if ( !defined('SITEPAD') && (version_compare( get_bloginfo( 'version' ), '6.8', '>=' )) ) {
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_speculative_loading" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_speculative_loading" name="speculation_loading" '.(!empty($speedycache->options['speculation_loading']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Edit Speculative Loading', 'speedycache').' <span class="speedycache-modal-settings-link" setting-id="speedycache_speculative_loading" style="display:'.(!empty($speedycache->options['speculation_loading']) ? 'inline-block' : 'none').';">- Settings</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Change how aggresive you want preloading/prefetching to happen.','speedycache').'</span>
				</div>
			</div>
			<div modal-id="speedycache_speculative_loading" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
						<div>'.esc_html__('Speculation Settings', 'speedycache').'</div>
						<div title="Close Modal" class="speedycache-close-modal">
							<span class="dashicons dashicons-no"></span>
						</div>
					</div>
					<div class="speedycache-modal-content">
						<p style="color:#666;margin-top:0 !important;"></p>

						<div class="speedycache-form-input">
							<label style="width:100%;">
								<span style="font-weight:500; margin-bottom:5px">'.esc_html__('Select the Speculation Mode', 'speedycache').'</span>
								<select name="speculation_mode" value="'.(!empty($speedycache->options['speculation_mode']) ? esc_attr($speedycache->options['speculation_mode']) : '').'">
									<option value="auto" '.(isset($speedycache->options['speculation_mode']) ? selected($speedycache->options['speculation_mode'], 'auto', false) : '').'>'.esc_html__('Auto', 'speedycache').'</option>
									<option value="prefetch" '.(isset($speedycache->options['speculation_mode']) ? selected($speedycache->options['speculation_mode'], 'prefetch', false) : '').'>'.esc_html__('Prefetch', 'speedycache').'</option>
									<option value="prerender" '.(isset($speedycache->options['speculation_mode']) ? selected($speedycache->options['speculation_mode'], 'prerender', false) : '').'>'.esc_html__('Prerender', 'speedycache').'</option>
									<option value="disabled" '.(isset($speedycache->options['speculation_mode']) ? selected($speedycache->options['speculation_mode'], 'disabled', false) : '').'>'.esc_html__('Disabled', 'speedycache').'</option>
								</select>
							</label>
						</div>
						<div class="speedycache-form-input">
							<label style="width:100%;">
								<span style="font-weight:500; margin-bottom:5px">'.esc_html__('Select Eagerness', 'speedycache').'</span>
								<select name="speculation_eagerness" value="'.(!empty($speedycache->options['speculation_eagerness']) ? esc_attr($speedycache->options['speculation_eagerness']) : '').'">
									<option value="auto" '.(isset($speedycache->options['speculation_eagerness']) ? selected($speedycache->options['speculation_eagerness'], 'auto', false) : '').'>'.esc_html__('Auto', 'speedycache').'</option>
									<option value="eager" '.(isset($speedycache->options['speculation_eagerness']) ? selected($speedycache->options['speculation_eagerness'], 'eager', false) : '').'>'.esc_html__('Eager', 'speedycache').'</option>
									<option value="moderate" '.(isset($speedycache->options['speculation_eagerness']) ? selected($speedycache->options['speculation_eagerness'], 'moderate', false) : '').'>'.esc_html__('Moderate', 'speedycache').'</option>
									<option value="conservative" '.(isset($speedycache->options['speculation_eagerness']) ? selected($speedycache->options['speculation_eagerness'], 'conservative', false) : '').'>'.esc_html__('Conservative', 'speedycache').'</option>
								</select>
							</label>
						</div>
					</div>
					<div class="speedycache-modal-footer">
						<button type="button" action="close">
							<span>'.esc_html__('Submit', 'speedycache').'</span>
						</button>
					</div>
				</div>
			</div>';
		}
				
		if(!defined('SITEPAD')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_dns_prefetch" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_dns_prefetch" name="dns_prefetch" '.(!empty($speedycache->options['dns_prefetch']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('DNS Prefetch', 'speedycache').' <span class="speedycache-modal-settings-link" setting-id="speedycache_dns_prefetch" style="display:'.(!empty($speedycache->options['dns_prefetch']) ? 'inline-block' : 'none').';">- Settings</span></span>
					<span class="speedycache-option-desc">'.esc_html__('DNS prefetching can make external files load faster.', 'speedycache').'</span>
				</div>
			</div>
			<div modal-id="speedycache_dns_prefetch" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
							<div>'.esc_html__('Prefetch DNS Requests', 'speedycache').'</div>
							<div title="Close Modal" class="speedycache-close-modal">
								<span class="dashicons dashicons-no"></span>
							</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<h3>'.esc_html__('How DNS Prefetch can help?', 'speedycache').'</h3>		
						<p>'.esc_html__('DNS prefetch can improve page load performance by resolving domain names in advance, so that the browser can start loading resources from those domains as soon as possible.', 'speedycache').'</p>
						
						<label><strong>'.esc_html__('URLs to prefetch', 'speedycache').'</strong>
						<span style="display:block;">'.esc_html__('Specify external hosts to be prefetched (no http:, one per line)', 'speedycache').'</span>
						<textarea name="dns_urls" style="width:100%" rows="4" placeholder="//example.com">'.(!empty($speedycache->options['dns_urls']) ? esc_html(implode("\n", $speedycache->options['dns_urls'])) : '').'</textarea>
						</label>
					</div>
					<div class="speedycache-modal-footer">
						<button type="button" action="close">
							<span>'.esc_html__('Submit', 'speedycache').'</span>
						</button>
					</div>
				</div>
			</div>';
		}

		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_preload_resources" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_preload_resources" name="preload_resources" '.(!empty($speedycache->options['preload_resources']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Preload Resources', 'speedycache').' <span class="speedycache-modal-settings-link" setting-id="speedycache_preload_resources" style="display:'.(!empty($speedycache->options['preload_resources']) ? 'inline-block' : 'none').';">- Settings</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Hints browser to load resources early.', 'speedycache').'</span>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'. esc_html__('Preload Resources', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'. esc_html__('Hints browser to load resources early.', 'speedycache').'</span>
				</div>
			</div>';

		}

		if(!defined('SITEPAD')){
			if(defined('SPEEDYCACHE_PRO')){
				echo '<div class="speedycache-option-wrap">
					<label for="speedycache_pre_connect" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_pre_connect" name="pre_connect" '. (!empty($speedycache->options['pre_connect']) ? 'checked' : '') .'/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name">'. esc_html__('PreConnect', 'speedycache').' <span class="speedycache-modal-settings-link" setting-id="speedycache_pre_connect" style="display:'. (!empty($speedycache->options['pre_connect']) ? 'inline-block' : 'none').';">- Settings</span></span>
						<span class="speedycache-option-desc">'.esc_html__('Establish early connections to speed up page load.', 'speedycache').'</span>
					</div>
				</div>';
			} else {
				echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'. esc_html__('Preconnect', 'speedycache') .'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'. esc_html__('Establish early connections to speed up page load.', 'speedycache').'</span>
				</div>
			</div>';
			}
		}

		self::save_btn();
		echo '</form>';
		
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div modal-id="speedycache_preload_resources" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
							<div>'.esc_html__('Preload Resource', 'speedycache').'</div>
							<div title="Close Modal" class="speedycache-close-modal">
								<span class="dashicons dashicons-no"></span>
							</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<form class="speedycache-pseudo-form" data-type="preload_resource_list">'.
						wp_kses(self::preload_modal_options('preload_resource', ['type' => true, 'crossorigin' => true, 'priority' => true,  'device' => true]), [
							'input' => ['type' => true, 'value' => true, 'style' => true, 'name' => true, 'placeholder' => true],
							'option' => ['value' => true],
							'select' => ['name' => true, 'required' => true],
							'label' => ['for' => true, 'style' => true],
							'div' => ['class' => true, 'style' => true],
							'span' => ['class' => true, 'title' => true, 'spdf-hover-tooltip' => true, 'spdf-tooltip-position' => true],
							]).'
						<div style="display:flex; justify-content:center;">
							<button type="submit" class="speedycache-button speedycache-btn-black speedycache-preloading-add">Add<span class="speedycache-spinner"></span></button>
						</div>
						</form>';
					
						echo '<p><strong>Note:</strong> Preloading too many resources can actually slow down your website, so it\'s important to only preload the resources that are absolutely necessary for the initial load. These might include fonts, image, CSS or JS files.</p>';

						echo '<div style="width:100%; overflow-x:scroll;"><table class="speedycache-table speedycache-preloading-table" data-type="preload_resource_list">
							<thead>
								<tr>
									<th class="speedycache-table-hitem" scope="col" width="70%">'.esc_html__('Resource', 'speedycache').'</th>
									<th class="speedycache-table-hitem" scope="col" width="15%">'. esc_html__('Type', 'speedycache').'</th>
									<th class="speedycache-table-hitem" scope="col" width="10%"><abbr title="Crossorigin">'. esc_html__('CS', 'speedycache').'</abbr></th>
									<th class="speedycache-table-hitem" scope="col" width="10%">'. esc_html__('Device', 'speedycache').'</th>
									<th class="speedycache-table-hitem" scope="col" width="10%">'. esc_html__('Fetch Priority', 'speedycache').'</th>
									<th class="speedycache-table-hitem" scope="col" width="5%"></th>
								</tr>
							</thead>
							<tbody>';
							
							if(empty($speedycache->options['preload_resource_list']) || !is_array($speedycache->options['preload_resource_list'])){
								echo '<tr><td colspan="6" align="center" class="speedycache-preloading-empty">No Resource Preload added yet</td></tr>';
							} else {
								foreach($speedycache->options['preload_resource_list'] as $pkey => $preload_resource){
									echo '<tr>
										<td>'.esc_url($preload_resource['resource']).'</td>
										<td>'.esc_html($preload_resource['type']).'</td>
										<td>'.(!empty($preload_resource['crossorigin']) ? 'Yes' : 'No').'</td>
										<td>'.(!empty($preload_resource['device']) ? esc_html($preload_resource['device']) : 'All').'</td>
										<td>'.(!empty($preload_resource['fetch_priority']) ? esc_html(ucfirst($preload_resource['fetch_priority'])) : 'Auto').'</td>
										<td data-key="'.esc_attr($pkey).'"><span class="dashicons dashicons-trash"></span></td>
									</tr>';
								}
							}
							
							echo '</tbody>
						</table>
						</div>
					</div>
				</div>
			</div>';
			
			if(!defined('SITEPAD')){
				echo'
				<div modal-id="speedycache_pre_connect" class="speedycache-modal">
					<div class="speedycache-modal-wrap">
						<div class="speedycache-modal-header">
								<div>'. esc_html__('Preconnect', 'speedycache').'</div>
								<div title="Close Modal" class="speedycache-close-modal">
									<span class="dashicons dashicons-no"></span>
								</div>
						</div>
						<div class="speedycache-modal-content speedycache-info-modal">
							<form class="speedycache-pseudo-form" data-type="pre_connect_list">								
							'.wp_kses(self::preload_modal_options('pre_connect', ['crossorigin' => true]), [
								'input' => ['type' => true, 'value' => true, 'style' => true, 'name' => true, 'placeholder' => true],
								'option' => ['value' => true],
								'select' => ['name' => true, 'required' => true],
								'label' => ['for' => true, 'style' => true],
								'div' => ['class' => true, 'style' => true],
								'span' => ['aria-label' => true, 'data-microtip-position' => true, 'role' => true],
								]).'
							<div style="display:flex; justify-content:center;">
								<button tabindex="" type="submit" class="speedycache-button speedycache-btn-black speedycache-preloading-add">Add<span class="speedycache-spinner"></span><span class="dashicons dashicons-yes speedycache-spinner-done"></span></button>
							</div>
							</form>';
							if(!empty($speedycache->options['pre_connect_list']) && count($speedycache->options['pre_connect_list']) > 6){
								echo '<p><strong>Note:</strong> A good rule of thumb is to limit the number of preconnects to 6-8. However, the exact number will vary depending on the specific website and the resources that are being loaded.</p>';
							}

							echo '<table class="speedycache-table speedycache-preloading-table" data-type="pre_connect_list">
								<thead>
									<tr>
										<th class="speedycache-table-hitem" scope="col" width="80%">'.esc_html__('Resource', 'speedycache').'</th>
										<th class="speedycache-table-hitem" scope="col" width="15%">'. esc_html__('Crossorigin', 'speedycache').'</th>
										<th class="speedycache-table-hitem" scope="col" width="5%"></th>
									</tr>
								</thead>
								<tbody>';
								
								if(empty($speedycache->options['pre_connect_list']) || !is_array($speedycache->options['pre_connect_list'])){
									echo '<tr><td colspan="4" align="center" class="speedycache-preloading-empty">'.esc_html__('No PreConnect added yet', 'speedycache').'</td></tr>';
								} else {
									foreach($speedycache->options['pre_connect_list'] as $pkey => $pre_connect){
										echo '<tr>
											<td>'.esc_html($pre_connect['resource']).'</td>
											<td>'.(!empty($pre_connect['crossorigin']) ? 'Yes' : 'No').'</td>
											<td data-key="'.esc_html($pkey).'"><span class="dashicons dashicons-trash"></span></td>
										</tr>';
									}
								}
								echo '</tbody>
							</table>
						</div>
					</div>
				</div>';
			}
		}
	}
	
	static function cdn_tab(){
		global $speedycache;
		
		$default_file_types = ['aac', 'css', 'eot', 'gif', 'jpeg', 'js', 'jpg', 'less', 'mp3', 'mp4', 'ogg', 'otf', 'pdf', 'png', 'svg', 'swf', 'ttf', 'webm', 'webp', 'woff', 'woff2'];

		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/cdn.svg" height="32" width="32"/> CDN Settings</h2>
		<form method="POST">';
		wp_nonce_field('speedycache_ajax_nonce');
		echo '<input type="hidden" value="speedycache_save_cdn_settings" name="action"/>
		<div class="speedycache-option-wrap">
			<label for="speedycache_enable_cdn" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_enable_cdn" name="enable_cdn" '.(!empty($speedycache->cdn['enabled']) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Enable CDN', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('This will start rewriting asset URL\'s to the CDN URL', 'speedycache').'</span>
			</div>
		</div>
		
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('Select CDN Provider', 'speedycache').'</label>
			</div>
			<div>
				<select id="speedycache-cdn-type" name="cdn_type" value="'.(!empty($speedycache->cdn['cdn_type']) ? esc_attr($speedycache->cdn['cdn_type']) : '').'">
					<option  value="cloudflare" '. (!empty($speedycache->cdn['cdn_type']) ? selected($speedycache->cdn['cdn_type'], 'cloudflare', false) : '').'>Cloudflare</option>
					<option value="bunny" '. (!empty($speedycache->cdn['cdn_type']) ? selected($speedycache->cdn['cdn_type'], 'bunny', false) : '').'>Bunny</option>
					<option value="other" '. (!empty($speedycache->cdn['cdn_type']) ? selected($speedycache->cdn['cdn_type'], 'other', false) : '').'>Others</option>
				</select>
			</div>
		</div>
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('CDN URL', 'speedycache').'</label>
				<span class="speedycache-option-desc">'.esc_html__('It is the URL that CDN Provider provides you.', 'speedycache').'</span>
			</div>
			<div>
				<input type="url" name="cdn_url" style="width:50%;" value="'.(!empty($speedycache->cdn['cdn_url']) ? esc_url($speedycache->cdn['cdn_url']) : '').'" id="speedycache-cdn-url" placeholder="https://cdn-url.com"/>
			</div>
		</div>
		
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('API Key', 'speedycache').'</label>
				<span class="speedycache-option-desc">'.esc_html__('API keys/ tokens are not required but used to purge cache on CDN when cache from SpeedyCache gets purged.', 'speedycache').'</span>
			</div>
			<div>
				<input type="text" name="cdn_key" style="width:50%;" id="speedycache-cdn-key" value="'.(!empty($speedycache->cdn['cdn_key']) ? esc_html($speedycache->cdn['cdn_key']) : '').'"/>
			</div>
		</div>
		
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('File Types', 'speedycache').'</label>
				<span class="speedycache-option-desc">'.esc_html__('Types of files you want to be served through the CDN(one file per line)', 'speedycache').'</span>
			</div>
			<div>
				<textarea name="file_types" style="width:50%;" rows="5">'.(!empty($speedycache->cdn['file_types']) ? esc_html(implode("\n", $speedycache->cdn['file_types'])) : esc_html(implode("\n", $default_file_types))).'</textarea>
			</div>
		</div>
		
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('Exclude Sources', 'speedycache').'</label>
				<span class="speedycache-option-desc">'.esc_html__('Files you do not want to be rewritten to a CDN url(one file per line).', 'speedycache').'</span>
			</div>
			<div>
				<textarea name="excludekeywords" style="width:50%;" rows="5">'.(!empty($speedycache->cdn['excludekeywords']) ? esc_html(implode("\n", $speedycache->cdn['excludekeywords'])) : '').'</textarea>
			</div>
		</div>
		
		<div class="speedycache-stacked-option-wrap">
			<div class="speedycache-option-info">
				<label class="speedycache-option-name">'.esc_html__('Specific Sources', 'speedycache').'</label>
				<span class="speedycache-option-desc">'.esc_html__('Specific files which you want to be rewritten using CDN URL(one file per line).', 'speedycache').'</span>
			</div>
			<div>
				<textarea name="keywords" style="width:50%;" rows="5">'.(!empty($speedycache->cdn['keywords']) ? esc_html(implode("\n", $speedycache->cdn['keywords'])) : '').'</textarea>
			</div>
		</div>';
		
		self::save_btn();
		
		echo '</form>';
	}
	
	static function excludes_tab(){
		
		$excludes = get_option('speedycache_exclude', []);

		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/excludes.svg" height="32" width="32"/> Exclude Settings</h2>
		<div class="speedycache-table-actions">
			<div class="speedycache-table-filter">
				<select id="speedycache-type-filter">
					<option value="">All</option>
					<option value="cookie">Cookies</option>
					<option value="js">JS</option>
					<option value="css">CSS</option>
					<option value="useragent">User Agent</option>
					<option value="page">Page</option>
				</select>
			</div>
			<div class="speedycach-table-add-new"><button class="speedycache-button speedycache-btn-black" id="speedycache_add_excludes">'.esc_html__('Add New Rule', 'speedycache').'</button></div>
		</div>
		<div class="speedycache-table speedycache-exclude-list" id="speedycache-exclude-list">
			<table>
			<thead>
				<tr role="row">
					<th>Type</th>
					<th>Prefix</th>
					<th>Content</th>
					<th>Actions</th>
				</tr>
			</thead>
			<tbody>';
				if(empty($excludes)){
					echo '<tr role="row">
						<td colspan="4">'.esc_html__('No exclude rule added yet','speedycache').'</td>
					</tr>';
				} else {
					foreach($excludes as $id => $exclude){
						echo '<tr role="row" data-id='.esc_attr($id).'>
							<td>'.esc_html($exclude['type']).'</td>
							<td>'.esc_html($exclude['prefix']).'</td>';
							if($exclude['prefix'] == 'post_id'){
								if(!is_array($exclude['content'])){
									$exclude['content'] = explode(',', $exclude['content']);
								}

								echo '<td>'.'#ID:';

								foreach($exclude['content'] as $exclude){
									$post = get_post($exclude);
									
									if(empty($post)){
										continue;
									}

									$post_link = get_permalink($post->ID);
									
									echo '<a href="'.esc_url($post_link).'" class="speedycache-tooltip-link" target="_blank">'.esc_html($exclude);
									
									// We show a tool tip with the excluded page URL and title
									echo '<div class="speedycache-link-tooltip">
									<h4>'.esc_html($post->post_title).'</h4>
									<p>'.esc_url($post_link).'</p>
									</div></a>';
								}
								
								echo '</td>';
							}
							else{
								echo'<td>'.esc_html($exclude['content']).'</td>';
							}
							echo'<td><button class="speedycache-button speedycache-delete-rule">Delete<span class="speedycache-spinner"></span></button>
						</tr>';
					}
				}
			echo '</tbody>
			</table>
		</div>
		
		<div modal-id="speedycache_add_excludes" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Add Exclude Rule', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content speedycache-info-modal">
					<form method="POST">
						<input type="hidden" name="action" value="speedycache_save_excludes"/>';
						wp_nonce_field('speedycache_ajax_nonce');
						echo '<div class="speedycache-input-wrap">
							<label for="speedycache-exclude-type">Exclude Type</label>
							<select name="type" id="speedycache-exclude-type" class="speedycache-100" required>
								<option value="page"/>Page</option>
								<option value="useragent"/>User-Agent</option>
								<option value="cookie"/>Cookie</option>
								<option value="css"/>CSS</option>
								<option value="js"/>JS</option>
							</select>
						</div>
						
						<div class="speedycache-input-wrap">
							<label for="speedycache-exclude-rule-prefix">Exclude</label>
							<select name="prefix" id="speedycache-exclude-rule-prefix" class="speedycache-100" required>
								<option selected="" value="" selected data-partof="page">Select a Value</option>
								<option value="homepage" data-partof="page">Home Page</option>
								<option value="category" data-partof="page">Categories</option>
								<option value="tag" data-partof="page">Tags</option>
								<option value="post" data-partof="page">Posts</option>
								<option value="page" data-partof="page">Pages</option>
								<option value="post_id" data-partof="page">Post ID</option>
								<option value="shortcode" data-partof="page">Shortcode</option>
								<option value="archive" data-partof="page">Archives</option>
								<option value="attachment" data-partof="page">Attachments</option>
								<option value="startwith" data-partof="page">Starts With</option>
								<option value="contain" data-partof="page,useragent,cookie,css,js">Contains</option>
								<option value="exact" data-partof="page">URI Is Equal To</option>';
								if (!defined('SITEPAD')){
									echo '<option value="woocommerce_items_in_cart" data-partof="cookie">has Woocommerce Items in Cart</option>';
								}
								echo'
							</select>
						</div>
						<div class="speedycache-input-wrap" style="display:none;">
							<label for="speedycache-exclude-rule-content">Content</label>
						</div>
						<div class="speedycache-exclude-btn-wrap">
							<button class="speedycache-button speedycache-btn-black">'.esc_html__('Save Rule', 'speedycache').'<span class="speedycache-spinner"></button>
						</div>
					</form>
				</div>
			</div>
		</div>';
	}
	
	static function media_tab(){
		global $speedycache;
		
		// Backward compatibility
		if(!empty($speedycache->options['lazy_load_keywords']) && is_string($speedycache->options['lazy_load_keywords'])){
			$speedycache->options['lazy_load_keywords'] = explode(',', $speedycache->options['lazy_load_keywords']);
		}

		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/media.svg" height="32" width="32"/> Media Settings</h2>
		<form method="POST">';
		wp_nonce_field('speedycache_ajax_nonce');
		
		echo '<input type="hidden" name="action" value="speedycache_save_media_settings"/>';
		if(!defined('SITEPAD')){
			echo'
			<div class="speedycache-option-wrap">
				<label for="speedycache_gravatar_cache" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_gravatar_cache" name="gravatar_cache" '.(!empty($speedycache->options['gravatar_cache']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Gravatar Cache', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Locally host Gravatar', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<input type="hidden" value="'.(isset($speedycache->options['lazy_load_placeholder']) ? esc_attr($speedycache->options['lazy_load_placeholder']) : '').'" id="speedycache_lazy_load_placeholder" name="lazy_load_placeholder"/>
				<input style="display: none;" type="checkbox" '.(isset($speedycache->options['lazy_load_exclude_full_size_img']) ? esc_attr($speedycache->options['lazy_load_exclude_full_size_img']) : '').' id="speedycache_lazy_load_exclude_full_size_img" name="lazy_load_exclude_full_size_img">
				
				<label for="speedycache_lazy_load" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_lazy_load" name="lazy_load" '.(!empty($speedycache->options['lazy_load']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Lazy Load', 'speedycache').' <span class="speedycache-modal-settings-link" setting-id="speedycache_lazy_load" style="display:'.(!empty($speedycache->options['lazy_load']) ? 'inline-block' : 'none').';">- Settings</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Load images and iframes when they enter the browsers viewport', 'speedycache').'</span>
				</div>
			</div>

			<!--SpeedyCache Lazy Load Modal Starts here-->
			<div modal-id="speedycache_lazy_load" class="speedycache-modal">
				<div class="speedycache-modal-wrap">
					<div class="speedycache-modal-header">
						<div>'.esc_html__('Lazy Load Settings', 'speedycache').'</div>
						<div title="Close Modal" class="speedycache-close-modal">
							<span class="dashicons dashicons-no"></span>
						</div>
					</div>
					<div class="speedycache-modal-content speedycache-info-modal">
						<div class="speedycache-modal-block">
							<h4>'.esc_html__('Image Placeholder', 'speedycache').'</h4>
							<p>'.esc_html__('Specify an image to be used as a placeholder while other images finish loading.', 'speedycache').'
								<a target="_blank" href="https://speedycache.com/docs/miscellaneous/lazy-load-images-and-iframes/">
								<span class="dashicons dashicons-info"></span>
								</a>
							</p>
							<div class="speedycache-form-input">
								<select name="lazy_load_placeholder" id="speedycache-ll-type" class="speedycache_lazy_load_placeholder speedycache-100" value="'.(!isset($speedycache->options['lazy_load_placeholder']) ? '' : esc_attr($speedycache->options['lazy_load_placeholder'])).'">
									<option value="default" '.((isset($speedycache->options['lazy_load_placeholder']) && $speedycache->options['lazy_load_placeholder'] == 'default') ? 'selected' : '').'>'.esc_html(preg_replace("/https?\:\/\//", '', esc_url(SPEEDYCACHE_URL))).'/assets/images/image-palceholder.png'.'</option>
									<option value="custom" '.((isset($speedycache->options['lazy_load_placeholder']) && $speedycache->options['lazy_load_placeholder'] == 'custom') ? 'selected' : '').'>'.esc_html__('Custom Placeholder', 'speedycache').'</option>
								</select>
							</div>';
							$hide_css_class = '';
						
							if(isset($speedycache->options['lazy_load_placeholder']) && $speedycache->options['lazy_load_placeholder'] != 'custom'){
								$hide_css_class = 'speedycache-hidden '; 
							}
							
							echo '<div class="speedycache-form-input">
								<input type="text" id="speedycache-custom-ll-url"  class="'.esc_attr($hide_css_class).'speedycache-100" placeholder="https://example.com/sample.jpg" name="lazy_load_placeholder_custom_url" value="'.(!isset($speedycache->options['lazy_load_placeholder_custom_url']) ? '' : esc_url($speedycache->options['lazy_load_placeholder_custom_url'])).'"/>
							</div>
						<div class="speedycache-modal-block">
							<h4>'.esc_html__('Exclude above fold images', 'speedycache').'</h4>
							<p>'.esc_html__('Number of images you want to exclude from getting lazyloaded from top of the screen', 'speedycache').'</p>
							<select name="exclude_above_fold">';

							foreach([0,1,2,3,4,5] as $exclude_no){
								$selected = '';
								if(isset($speedycache->options['exclude_above_fold']) && $exclude_no == $speedycache->options['exclude_above_fold']){
									$selected = 'selected';
								}elseif(!isset($speedycache->options['exclude_above_fold']) && $exclude_no == 2){
									$selected = 'selected';
								}

								echo '<option value="'.esc_attr($exclude_no).'" '.esc_attr($selected).'>'.esc_html($exclude_no).'</option>';
							}
							echo '</select>
						</div>

						<div class="speedycache-modal-block">
							<h4>'.esc_html__('Exclude Sources', 'speedycache').'</h4>
							<p>'.esc_html__('It is enough to write a keyword such as', 'speedycache').' <strong>home.jpg or iframe or .gif</strong> instead of full url.</p>
							<div class="speedycache-form-input">
								<label for="speedycache-full-width">
									'.esc_html__('Add Keyword', 'speedycache').'
									<span class="speedycache-input-desc">('.esc_html__('one keyword per line', 'speedycache').')</span>
									<textarea name="lazy_load_keywords" class="speedycache-100" rows="5">'.(empty($speedycache->options['lazy_load_keywords']) ? '' : esc_attr(implode("\n", $speedycache->options['lazy_load_keywords']))).'</textarea>
								</label>
							</div>';
						echo '</div>
					</div></div>
					<div class="speedycache-modal-footer">
						<button type="button" action="close">
							<span>'.esc_html__('Submit', 'speedycache').'</span>
						</button>
					</div>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Lazy Load', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Load images and iframes when they enter the browsers viewport', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_image_dimensions" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_image_dimensions" name="image_dimensions" '.(!empty($speedycache->options['image_dimensions']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Image Dimensions', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Adds dimensions to the image, to reduce CLS', 'speedycache').'</span>
				</div>
			</div>';	
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Image Dimensions', 'speedycache').'<span class="speedycache-premium-tag">'. esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Adds dimensions to the image, to reduce CLS', 'speedycache').'</span>
				</div>
			</div>';
		}

		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_local_gfonts" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_local_gfonts" name="local_gfonts" '. (!empty($speedycache->options['local_gfonts']) ? 'checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Local Google Fonts', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Loads google fonts from your local server', 'speedycache').'</span>
				</div>
			</div>';
			
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox"disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Local Google Fonts', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Loads google fonts from your local server', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		if(defined('SPEEDYCACHE_PRO')){
			echo '<div class="speedycache-option-wrap">
				<label for="speedycache_google_fonts" class="speedycache-custom-checkbox">
					<input type="checkbox" id="speedycache_google_fonts" name="google_fonts" '.(!empty($speedycache->options['google_fonts']) ? ' checked' : '').'/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Google Fonts', 'speedycache').'</span>
					<span class="speedycache-option-desc">'.esc_html__('Load Google Fonts asynchronously', 'speedycache').'</span>
				</div>
			</div>';
		} else {
			echo '<div class="speedycache-option-wrap speedycache-disabled">
				<label class="speedycache-custom-checkbox">
					<input type="checkbox" disabled/>
					<div class="speedycache-input-slider"></div>
				</label>
				<div class="speedycache-option-info">
					<span class="speedycache-option-name">'.esc_html__('Google Fonts', 'speedycache').'<span class="speedycache-premium-tag">'.esc_html__('Premium', 'speedycache').'</span></span>
					<span class="speedycache-option-desc">'.esc_html__('Load Google Fonts asynchronously', 'speedycache').'</span>
				</div>
			</div>';
		}
		
		echo '<div class="speedycache-option-wrap">
			<label for="speedycache_font_rendering" class="speedycache-custom-checkbox">
				<input type="checkbox" id="speedycache_font_rendering" name="font_rendering" '. (!empty($speedycache->options['font_rendering']) ? 'checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name">'.esc_html__('Improve Font Rendering', 'speedycache').'</span>
				<span class="speedycache-option-desc">'.esc_html__('Improved Font rendeing by adding text-rendring CSS.', 'speedycache').'</span>
			</div>
		</div>';

		self::save_btn();
		echo '</form>';
	}
	
	static function settings_tab(){
		echo '<h2><img src="'.esc_url(SPEEDYCACHE_URL).'/assets/images/icons/settings.svg" height="32" width="32"/> '.esc_html__('General Settings', 'speedycache').'</h2>';
		
		$roles = get_editable_roles();
		
		if(!empty($roles)){
			$saved_roles = get_option('speedycache_deletion_roles', []);
			
			echo '<div class="speedycache-option-info">
			<span class="speedycache-option-name">'.esc_html__('Can Delete Cache', 'speedycache').'</span>
			<span class="speedycache-option-desc">'.esc_html__('Allows roles to delete cache using Admin bar and post links, Admin is included by default', 'speedycache').'</span>
			<form method="POST">';
			wp_nonce_field('speedycache_ajax_nonce');
		
			echo '<input type="hidden" name="action" value="speedycache_save_deletion_role_settings"/>
			<div class="speedycache-deletion-roles">';
			foreach($roles as $key => $role){
				// Admin will always have access to everything, so no need to give option to be able to enable it.
				if($key == 'administrator'){
					continue;
				}

				// We need to make sure the user has capability to publish_posts
				// Giving access to anyone other than this capability does not makes sense
				// As giving option to enable subscriber could cause issue becuase of human error.
				if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts', $role['capabilities'])){
					continue;
				}
				
				$checked = false;
				if(in_array($key, $saved_roles)){
					$checked = 'checked';
				}

				echo '<label for="speedycache-admin-bar-cap-'.esc_attr($key).'"><input type="checkbox" id="speedycache-admin-bar-cap-'.esc_attr($key).'"name="cache_deletion_roles[]" value="'.esc_attr($key).'" '.esc_attr($checked).'/>'.esc_html($role['name']).'</label>';
			}
			echo '</div>
			<div class="speedycache-btn-spl-wrapper"><button class="speedycache-button speedycache-btn-black" style="margin-top:10px;">Save<span class="speedycache-spinner"></span></button></div></form></div>';
		}

		echo '<div class="speedycache-option-info" style="margin-top:20px;">
		<label class="speedycache-option-name">'.esc_html__('Import / Export Settings', 'speedycache').'</label>
		<span class="speedycache-option-desc" style="margin-bottom:10px;">'.esc_html__('Imports SpeedyCache Settings from another site or Exports your current SpeedyCache Settings as a JSON file', 'speedycache').'</span>
		</div>
		<div>
			<select id="speedycache-import-export" name="img-exp">
				<option value="import">Import</option>
				<option value="export">Export</option>
			</select>
		</div>';

		echo '<!-- Import Section -->
		<form method="POST" enctype="multipart/form-data">
		<input type="hidden" name="action" value="speedycache_import_settings"/>
		<div class="speedycache-option-info speedycache-import-block" style="display:block;">
			<span class="speedycache-option-desc">'.esc_html__('Select a JSON file containing SpeedyCache Settings. This will overwrite your current SpeedyCache Settings', 'speedycache').'</span>
			<input type="file" name="speedycache_import_file" id="speedycache_import_file" accept=".json" required />
			<button class="speedycache-button speedycache-btn-black speedycache-import-settings" style="margin-top:10px;">Import Settings<span class="speedycache-spinner"></span></button>
		</div>
		</form>';

		echo '<!-- Export Section -->
		<form method="POST" enctype="multipart/form-data">
		<input type="hidden" name="action" value="speedycache_export_settings"/>
		<div class="speedycache-option-info speedycache-export-block" style="display:none;">
			<span class="speedycache-option-desc">'.esc_html__('Click the button below to download the current SpeedyCache settings as a JSON file', 'speedycache').'</span>
			<button class="speedycache-button speedycache-btn-black speedycache-export-settings" style="margin-top:10px;">Download Export File<span class="speedycache-spinner"></span></button>
		</div>
		</form>';
	}
	
	static  function preload_modal_options($field_name, $fields){
		if(empty($fields)){
			return '';
		}

		switch($field_name){
			case 'pre_connect':
				$placeholder = 'https://fonts.google.com';
				break;

			default:
				$placeholder = site_url() . '/' . (defined('SITEPAD') ? 'sitepad-data' : 'wp-content') . '/uploads/image.jpg';
		}

		$html = '<div class="speedycache-preloading-options">
		<div class="speedycache-stacked-label" style="width:100%;">
			<label style="width:100%;">
				<span>Resource URL <span spdf-hover-tooltip="Required field" spdf-tooltip-position="bottom">*</span></span>
				<input type="text" name="resource" style="width:100%;" placeholder="'.esc_html($placeholder).'" required/>
			</label>
		</div>';
		
		$html .= '<div class="speedycache-preload-checkboxes">';
		if(isset($fields['parent_selector'])){
			$html .= '<label><input type="checkbox" name="parent_selector" value="true"/>Use Parent Selector</label>';
		}
		
		if(isset($fields['crossorigin'])){
			$html .= '<label><input type="checkbox" name="crossorigin" value="true"/>Crossorigin</label>';
		}
		
		$html .= '</div>';
		
		if(isset($fields['type'])){
			$html .= '<div class="speedycache-stacked-label"><label><span>Resource Type <span spdf-hover-tooltip="Required field" spdf-tooltip-position="top">*</span></span><select name="type" required>
				<option value="">Select Type</option>
				<option value="image">Image</option>
				<option value="font">Font</option>
				<option value="script">Script</option>
				<option value="style">Style</option>
				<option value="audio">Audio</option>"
				<option value="document">Document</option>
				<option value="video">Video</option>
			</select></label></div>';
		}
		
		if(isset($fields['priority'])){
			$html .= '<div class="speedycache-stacked-label"><label>
			<span>Fetch Priority</span>
			<select name="fetch_priority">
				<option value="" selected>Auto</option>
				<option value="high">High</option>
				<option value="low">Low</option>
			</select></label>
			</div>';
		}
		
		if(isset($fields['device'])){
			$html .= '<div class="speedycache-stacked-label"><label>
			<span>Device <span class="dashicons dashicons-editor-help" spdf-hover-tooltip="For this to work, you will need to enable Mobile Override and Mobile Cache options, this is not a required field" spdf-tooltip-position="top"></span></span>
			<select name="device">
				<option value="" selected>All</option>
				<option value="desktop">Desktop</option>
				<option value="mobile">Mobile</option>
			</select></label>
			</div>';
		}
		
		$html .= '</div>';
		
		return $html;

	}
	
	static function pro_notice($tab_name){
		echo '<h2>'.esc_html($tab_name).'</h2>
		<div class="notice notice-warning">
        <p>'.esc_html__('This is a part of SpeedyCache Pro, so update/upgrade to pro to utilize this feature', 'speedycache').'</p>
    </div>';
	}
	
	static function save_btn(){
		echo '<div class="speedycache-save-settings-wrapper"><button class="speedycache-button speedycache-btn-black">'.esc_html__('Save Settings', 'speedycache').'<span class="speedycache-spinner"></span><svg class="speedycache-spinner-done" xmlns="http://www.w3.org/2000/svg" height="15px" viewBox="0 -960 960 960" width="15px" fill="#FFF"><path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/></svg></button></div>';
	}
	
	static function pro_upsell(){

		$features = [
			'Delay JS Execution',
			'Defer JS Loading',
			'Lazy Load Iframes',
			'Database Cleanup',
			'Critical CSS',
			'and More...',
		];

		echo '<div class="speedycache-promo-modern-card">
			<div class="speedycache-promo-header-group">
			<h3 class="speedycache-promo-title">SpeedyCache</h3>
			<span class="speedycache-promo-badge-pro">Pro</span>
			</div>

			<p class="speedycache-promo-desc">'.esc_html__('Unlock advanced performance features.', 'speedycache').'</p>

			<ul class="speedycache-promo-feature-list">';
			foreach($features as $feature){
				echo '<li class="speedycache-promo-feature-item">
					<div class="speedycache-promo-check-circle">
						<div class="speedycache-promo-check-icon"></div>
					</div>
					'.esc_html($feature).'
				</li>';
			}
			echo '</ul>

			<a href="https://speedycache.com/pricing/?utm_source=plugin_settings" class="speedycache-promo-btn-main" target="_blank">
				<span class="speedycache-promo-btn-text">'.esc_html__('Upgrade to Pro', 'speedycache').'</span>
				<span class="speedycache-promo-arrow">&rarr;</span>
			</a>
		</div>';
	}
}

ajax.php000064400000053201151526414160006206 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Ajax{

	static function hooks(){
		add_action('wp_ajax_siteseo_save_titles_meta_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_save_sitemap_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_save_indexing_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_save_advanced_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_save_social_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_save_analytics_toggle', '\SiteSEO\Ajax::save_toggle_state');
		add_action('wp_ajax_siteseo_generate_bing_api_key', '\SiteSEO\Ajax::generate_bing_api_key');
		add_action('wp_ajax_siteseo_url_submitter_submit', '\SiteSEO\Ajax::instant_indexing');
		add_action('wp_ajax_siteseo_refresh_analysis', '\SiteSEO\Ajax::refresh_seo_analysis');
		add_action('wp_ajax_siteseo_export_settings', '\SiteSEO\Ajax::export_settings');
		add_action('wp_ajax_siteseo_import_settings', '\SiteSEO\Ajax::import_settings');
		add_action('wp_ajax_siteseo_reset_settings', '\SiteSEO\Ajax::reset_settings');
		add_action('wp_ajax_siteseo_migrate_seo', '\SiteSEO\Ajax::handle_import');
		add_action('wp_ajax_siteseo_dismiss_intro', '\SiteSEO\Ajax::dismiss_intro');
		add_action('wp_ajax_siteseo_save_universal_metabox', '\SiteSEO\Ajax::save_universal_metabox');
		add_action('wp_ajax_siteseo_resolve_variables', '\SiteSEO\Ajax::resolve_variables');
		add_action('wp_ajax_siteseo_clear_indexing_history', '\SiteSEO\Ajax::clear_indexing_history');
		add_action('wp_ajax_siteseo_close_update_notice', '\SiteSEO\Ajax::close_update_notice');
		
		// This is just to make sure, close of update notice works.
		if(isset($_GET['action']) && 'siteseo_close_update_notice' === sanitize_text_field(wp_unslash($_GET['action']))){
			add_filter('softaculous_plugin_update_notice', 'siteseo_plugin_update_notice_filter');
		}
		
		// Onboarding Actions
		add_action('wp_ajax_siteseo_save_onboarding_settings', '\SiteSEO\Ajax::save_onboarding_settings');
	}

	static function handle_import(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!siteseo_user_can('manage_options')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}
		
		$plugin = !empty($_POST['plugin']) ? sanitize_text_field(wp_unslash($_POST['plugin'])) : '';
		
		switch($plugin){
			case 'wordpress-seo':
				$result = \SiteSEO\Import::yoast_seo();
				break;
			case 'all-in-one-seo-pack':
				$result = \SiteSEO\Import::aio_seo();
				break;
			case 'autodescription':
				$result = \SiteSEO\Import::seo_framework();
				break;
			case 'wp-seopress':
				$result = \SiteSEO\Import::seo_press();
				break;
			case 'seo-by-rank-math':
				$result = \SiteSEO\Import::rank_math();
				break;
			case 'slim-seo':
				$result = \SiteSEO\Import::slim_seo();
				break;
			case 'surerank':
				$result = \SiteSEO\Import::surerank();
				break;
			default:
				throw new \Exception('Invalid plugin selected');
		}
		
		if(empty($result)){
			wp_send_json_error(['message' => __('Invalid plugin selected', 'siteseo')]);
		}
		

		update_option('siteseo_last_migration_log', $result['log'], false);
		wp_send_json_success(['message' => $result['message']]);
	}

	static function reset_settings(){

		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}
		
		$options = [
			'siteseo_toggle',
			'siteseo_titles_option_name',
			'siteseo_social_option_name',
			'siteseo_advanced_option_name',
			'siteseo_instant_indexing_option_name',
			'siteseo_xml_sitemap_option_name',
			'siteseo_google_analytics_option_name',
			'siteseo_dismiss_intro',
			'siteseo_pro_options'
		];

		foreach($options as $option){
			delete_option($option);
		}

		wp_send_json_success(['message' => esc_html__('Settings reset successfully.', 'siteseo')]);

	}

	static function import_settings(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}
		
		if(!isset($_FILES['import_file'])){
			wp_send_json_error(array('message' => 'No file was uploaded.'));
		}
		
		// If name or tmp path is not available return
		if(empty($_FILES['import_file']['name']) || empty($_FILES['import_file']['tmp_name'])){
			wp_send_json_error(array('message' => 'No file was uploaded.'));
		}

		$imported_file = $_FILES['import_file']['tmp_name'];
		$filename = sanitize_file_name($_FILES['import_file']['name']);
		$file_extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

		// Verify file exists and is readable
		if(!file_exists($imported_file) || !is_readable($imported_file) || !is_uploaded_file($imported_file)){
			wp_send_json_error(array('message' => __('Uploaded file is not readable.', 'siteseo')));
		}
		
		$mime_type = sanitize_text_field(wp_unslash($_FILES['import_file']['type']));
		
		if($mime_type !== 'application/json'){
			wp_send_json_error(array('message' => __('Invalid mime type. The uploaded file has invalid mime type', 'siteseo')));
		}

		// Making sure is the correct file format
		if($file_extension !== 'json') {
			wp_send_json_error(array('message' => __('Invalid file type. Please upload a JSON file.', 'siteseo')));
		}
		
		$file_contents = file_get_contents($imported_file);

		$settings = json_decode($file_contents, true);

		if(json_last_error() !== JSON_ERROR_NONE){
			wp_send_json_error(array('message' => __('Invalid JSON file.', 'siteseo')));
		}
		
		if(empty($settings) || !is_array($settings)){
			wp_send_json_error(array('message' => __('Invalid settings format.', 'siteseo')));
		}

		$settings = map_deep(wp_unslash($settings), 'sanitize_textarea_field');

		if(isset($settings['siteseo_titles_option_name'])){
			update_option('siteseo_titles_option_name', $settings['siteseo_titles_option_name']);
		}
		
		if(isset($settings['siteseo_social_option_name'])){
			update_option('siteseo_social_option_name', $settings['siteseo_social_option_name']);
		}
		
		if(isset($settings['siteseo_xml_sitemap_option_name'])){
			update_option('siteseo_xml_sitemap_option_name', $settings['siteseo_xml_sitemap_option_name']);
		}
		
		if(isset($settings['siteseo_toggle'])){
			update_option('siteseo_toggle', $settings['siteseo_toggle']);
		}
		
		if(isset($settings['siteseo_advanced_option_name'])){
			update_option('siteseo_advanced_option_name', $settings['siteseo_advanced_option_name']);
		}
		
		if(isset($settings['siteseo_instant_indexing_option_name'])){
			update_option('siteseo_instant_indexing_option_name', $settings['siteseo_instant_indexing_option_name']);
		}
		
		if(isset($settings['siteseo_google_analytics_option_name'])){
			update_option('siteseo_google_analytics_option_name', $settings['siteseo_google_analytics_option_name']);
		}
		
		// Pro
		if(isset($settings['siteseo_pro_options'])){
			update_option('siteseo_pro_options', $settings['siteseo_pro_options']);
		}
		

		wp_send_json_success(['message' => esc_html__('Settings imported successfully.', 'siteseo')]);	
	}
	
	static function export_settings(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}

		$export_data = array(
			'siteseo_titles_option_name' => get_option('siteseo_titles_option_name'),
			'siteseo_social_option_name' => get_option('siteseo_social_option_name'),
			'siteseo_xml_sitemap_option_name' => get_option('siteseo_xml_sitemap_option_name'),
			'siteseo_toggle' => get_option('siteseo_toggle'),
			'siteseo_google_analytics_option_name' => get_option('siteseo_google_analytics_option_name'),
			'siteseo_instant_indexing_option_name' => get_option('siteseo_instant_indexing_option_name'),
			'siteseo_advanced_option_name' => get_option('siteseo_advanced_option_name'),
			'siteseo_pro_options' =>get_option('siteseo_pro_options'),
		);

		$file_name = 'siteseo-settings-export-' . current_time('m-d-Y') . '.json';

		header('Content-Type: application/json');
		header('Content-Disposition: attachment; filename="'.$file_name.'"');
		header('Cache-Control: no-cache, no-store, must-revalidate');
		header('Pragma: no-cache');
		header('Expires: 0');
		
		echo wp_json_encode($export_data);		
		exit;
	}

	static function refresh_seo_analysis(){

		check_ajax_referer('siteseo_admin_nonce', 'nonce');

		if(!current_user_can('siteseo_manage')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}

		$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
		$post_type = isset($_POST['post_type']) ? sanitize_text_field(wp_unslash($_POST['post_type'])) : '';
		$target_keywords = isset($_POST['target_keywords']) ? sanitize_text_field(wp_unslash($_POST['target_keywords'])) : '';
		
		$post = get_post($post_id);
		if(!$post || !current_user_can('edit_post', $post_id)){
			wp_send_json_error(['message' => __('Invalid post or insufficient permissions', 'siteseo')]);
		}
		
		update_post_meta($post_id, '_siteseo_analysis_target_kw', $target_keywords);
	
		$analysis_data = \SiteSEO\Metaboxes\Analysis::perform_seo_analysis($post);

		update_post_meta($post_id, '_siteseo_analysis_data', $analysis_data);

		ob_start();
		\SiteSEO\Metaboxes\Analysis::display_seo_analysis($post);
		$analysis_html = ob_get_clean();

		wp_send_json_success([
			'html' => $analysis_html,
			'analysis_data' => $analysis_data
		]);
	}
	
	static function instant_indexing(){
		
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!siteseo_user_can('manage_instant_indexing')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}
		
		// Validate input
		if(!isset($_POST['search_engine'], $_POST['urls'])){
			wp_send_json_error(['message' => esc_html__('Missing required parameters', 'siteseo')]);
		}
	
		$urls = sanitize_textarea_field(wp_unslash($_POST['urls']));
	
		$options = get_option('siteseo_instant_indexing_option_name');
		$google_api_key = isset($options['instant_indexing_google_api_key']) ? $options['instant_indexing_google_api_key'] : '';
		$bing_api_key = isset($options['instant_indexing_bing_api_key']) ? $options['instant_indexing_bing_api_key'] : '';
		$url_list = array_filter(array_map('trim', explode("\n", $urls))); 
	
		if(empty($url_list)){
			wp_send_json_error(['message' => 'No valid URLs provided']);
		}

		$response = [];

		try{

			if(!empty($options['engines']['google']) && !empty($google_api_key)){
				$response['google'] = \SiteSEO\InstantIndexing::submit_urls_to_google($url_list);	
			} 

			if(!empty($options['engines']['bing']) && !empty($bing_api_key)){
				$response['bing'] = \SiteSEO\InstantIndexing::submit_urls_to_bing($url_list, $bing_api_key);
			}

			if(empty($response)){
				wp_send_json_error(['message' => 'No search engines configured or missing API keys']);
			}
			
			$res_google = !empty($response['google']) ? $response['google'] : null;
			$res_bing = !empty($response['bing']) ? $response['bing'] : null;
			
			\SiteSEO\InstantIndexing::save_index_history($url_list, $res_google, $res_bing, null);
			
			wp_send_json_success([
				'message' => 'URLs submitted successfully', 
				'details' => $response
			]);

		} catch(\Exception $e){
			wp_send_json_error(['message' => $e->getMessage()]);
		}
    }
	
	static function generate_bing_api_key(){
		
		if(!check_ajax_referer('siteseo_admin_nonce', 'nonce', false)){
			wp_send_json_error('Invalid nonce');
			return;
		}
		
		if(!siteseo_user_can('manage_instant_indexing')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}

		$lowercase = range('a', 'z');
		$uppercase = range('A', 'Z');
		$numbers = range('0', '9');
		$dash = ['-'];

		$characters = array_merge($lowercase, $uppercase, $numbers, $dash);
		$characters_length = count($characters);

		$length = 32;
		$api_key = '';

		for($i = 0; $i < $length; $i++){
			$api_key .= $characters[random_int(0, $characters_length - 1)];
		}

		wp_send_json_success(['api_key' => $api_key]);
	}
	
	static function save_toggle_state(){

		check_ajax_referer('siteseo_toggle_nonce', 'nonce');

		if(!current_user_can('manage_options')){
			wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'siteseo')]);
		}
		
		$action = isset($_POST['action']) ? sanitize_text_field(wp_unslash($_POST['action'])) : '';
		switch($action){
			case 'siteseo_save_titles_meta_toggle':
				$toggle_key = 'toggle-titles';
				break;
			case 'siteseo_save_sitemap_toggle':
				$toggle_key = 'toggle-xml-sitemap';
				break;
			case 'siteseo_save_indexing_toggle':
				$toggle_key = 'toggle-instant-indexing';
				break;
			case 'siteseo_save_advanced_toggle':
				$toggle_key = 'toggle-advanced';
				break;
			case 'siteseo_save_social_toggle':
				$toggle_key = 'toggle-social';
				break;
			case 'siteseo_save_analytics_toggle':
				$toggle_key = 'toggle-google-analytics';
				break;
			default:
				wp_send_json_error(['message' => __('Invalid action', 'siteseo')]);
				return;
		}

		$toggle_value = isset($_POST['toggle_value']) ? sanitize_text_field(wp_unslash($_POST['toggle_value'])) : '0';

		$options = get_option('siteseo_toggle', []);
		$options[$toggle_key] = $toggle_value;
		$updated = update_option('siteseo_toggle', $options);

		if($updated){
			wp_send_json_success([
				'message' => ucfirst($toggle_key) . ' toggle state saved successfully',
				'value' => $toggle_value
			]);
		}

		wp_send_json_error(['message' => __('Failed to save toggle state', 'siteseo')]);
	}	
	
	static function save_onboarding_settings(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(__('You do not have required permission to edit this file.', 'siteseo'));
		}
		
		if(empty($_POST['step'])){
			wp_send_json_error(['message' => __('Could not figure out the current step', 'siteseo')]);
		}
		
		$step_name = !empty($_POST['step']) ? sanitize_text_field(wp_unslash($_POST['step'])) : '';
		
		switch($step_name){
			case 'your-site':
				$title_options = get_option('siteseo_titles_option_name', []);
				$social_options = get_option('siteseo_social_option_name', []);

				if(!empty($_POST['data']['website_name'])){
					$title_options['titles_home_site_title'] = sanitize_text_field(wp_unslash($_POST['data']['website_name']));
				}

				if(!empty($_POST['data']['alternate_site_name'])){
					$title_options['titles_home_site_title_alt'] = sanitize_text_field(wp_unslash($_POST['data']['alternate_site_name']));
				}

				if(!empty($_POST['data']['site_type'])){
					$social_options['social_knowledge_type'] = sanitize_text_field(wp_unslash($_POST['data']['site_type']));
				}

				if(!empty($_POST['data']['organization_name'])){
					$social_options['social_knowledge_name'] = sanitize_text_field(wp_unslash($_POST['data']['organization_name']));
				}

				if(!empty($_POST['data']['organization_logo'])){
					$social_options['social_knowledge_img'] = sanitize_url(wp_unslash($_POST['data']['organization_logo']));
				}

				if(!empty($_POST['data']['social_fb'])){
					$social_options['social_accounts_facebook'] = sanitize_url(wp_unslash($_POST['data']['social_fb']));
				}

				if(!empty($_POST['data']['social_x'])){
					$social_options['social_accounts_twitter'] = sanitize_text_field(wp_unslash($_POST['data']['social_x']));
				}

				if(!empty($_POST['data']['social_additional'])){
					$social_options['social_accounts_additional'] = explode("\n", sanitize_textarea_field(wp_unslash($_POST['data']['social_additional'])));
				}

				update_option('siteseo_titles_option_name', $title_options);
				update_option('siteseo_social_option_name', $social_options);

				wp_send_json_success();
				break;

			case 'indexing':

				if(empty($_POST['data'])){
					break;
				}

				$data = map_deep(wp_unslash($_POST['data']), 'sanitize_text_field');
				$site_status = !empty($data['site_status']) ? $data['site_status'] : '';

				if(empty($site_status)){
					wp_send_json_error(['message' => __('Request data did not reach the backend', 'siteseo')]);
				}

				$title_options = get_option('siteseo_titles_option_name', []);
				
				if($site_status == 'underconstruction'){
					$title_options['titles_noindex'] = true;
					update_option('siteseo_titles_option_name', $title_options);
					wp_send_json_success();
				}
				
				// Saving Post type indexing values
				if(!empty($data['post_types'])){
					if(!is_array($data['post_types'])){
						$data['post_types'] = [$data['post_types']];
					}

					$post_types = get_post_types(['public' =>  true, 'show_ui' => true], 'objects', 'and');
					unset($post_types['attachment']);
					
					foreach($post_types as $post){
						if(in_array($post->name, $data['post_types'])){
							$title_options['titles_single_titles'][$post->name]['noindex'] = $post->name;
						}
					}
				}
				
				// Saving Taxonomies indexing values
				if(!empty($data['taxonomies'])){
					if(!is_array($data['taxonomies'])){
						$data['taxonomies'] = [$data['taxonomies']];
					}

					$taxonomies = get_taxonomies(['public' =>  true, 'show_ui' => true], 'objects', 'and');

					foreach($taxonomies as $taxonomy){
						if(in_array($taxonomy->name, $data['taxonomies'])){
							$title_options['titles_tax_titles'][$taxonomy->name]['noindex'] = $taxonomy->name;
						}
					}
				}

				update_option('siteseo_titles_option_name', $title_options);
				wp_send_json_success();
				
				break;
				
			case 'advanced':
				$data = map_deep(wp_unslash($_POST['data']), 'sanitize_text_field');
				$advanced_options = get_option('siteseo_advanced_option_name');

				$title_options = get_option('siteseo_titles_option_name', []);				
				$title_options['titles_archives_author_noindex'] = isset($data['author_noindex']) ? $data['author_noindex'] : '';

				$advanced_options['advanced_attachments_file'] = isset($data['redirect_attachment']) ? $data['redirect_attachment'] : '';
				$advanced_options['advanced_category_url'] = isset($data['category_url']) ? $data['category_url'] : '';
				$advanced_options['appearance_universal_metabox_disable'] = isset($data['universal_seo_metabox']) ? '' : '1';
				$advanced_options['appearance_universal_metabox'] = isset($data['universal_seo_metabox']) ? '1' : '';
				
				update_option('siteseo_titles_option_name', $title_options);
				update_option('siteseo_advanced_option_name', $advanced_options);
				wp_send_json_success();
				break;
		}
	}
	
	static function dismiss_intro(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('siteseo_manage')){
			wp_send_json_error(__('You do not have required permission to edit this file.', 'siteseo'));
		}
		
		update_option('siteseo_dismiss_intro', time());
	}
	
	static function save_universal_metabox(){
		check_ajax_referer('siteseo_universal_nonce', 'security');
		
		if(!current_user_can('siteseo_manage') || !siteseo_user_can_metabox()){
			wp_send_json_error(__('You do not have required permission to edit this file.', 'siteseo'));
		}
		
		if(empty($_POST['post_id'])){
			wp_send_json_error(__('Post ID not found', 'siteseo'));
		}
		
		$post_id = sanitize_text_field(wp_unslash($_POST['post_id']));

		if(!current_user_can('edit_post', $post_id)){
			wp_send_json_error(__('You do not have required permission to edit this file.', 'siteseo'));
		}

		$post = get_post($post_id);
		
		\SiteSEO\Metaboxes\Settings::save_metabox($post_id, $post);
	}
	
	static function resolve_variables(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('siteseo_manage')){
			wp_send_json_error(__('You do not have required permission to edit this file.', 'siteseo'));
		}

		if(empty($_POST['content']) || empty($_POST['post_id'])){
			wp_send_json_error(__('The required content or ID is empty', 'siteseo'));
		}
		
		global $post, $wp_query;
		
		$post_id = (int) sanitize_text_field(wp_unslash($_POST['post_id']));
		$content = sanitize_text_field(wp_unslash($_POST['content']));
		
		if(!current_user_can('edit_post', $post_id)){
			wp_send_json_error(__('You do not have permission to access this post', 'siteseo'));
		}

		$tmp_post = $post;
		$post = get_post($post_id);
		$replaced_content = \SiteSEO\TitlesMetas::replace_variables($content, true);
		$post = $tmp_post;

		wp_send_json_success($replaced_content);
	}
	
	static function clear_indexing_history(){
		check_ajax_referer('siteseo_admin_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(__('You do not have required permission to clear indexing history.', 'siteseo'));
		}
		
		global $siteseo;
		
		$indexing_history = $siteseo->instant_settings;
    
		if(is_array($indexing_history) && isset($indexing_history['indexing_history'])){
			unset($indexing_history['indexing_history']);
			update_option('siteseo_instant_indexing_option_name', $indexing_history);
		}
    
		wp_send_json_success();
	}
	
	static function close_update_notice(){
		check_ajax_referer('siteseo_promo_nonce', 'security');

		if(!current_user_can('manage_options')){
			wp_send_json_error('You don\'t have privilege to close this notice!');
		}

		$plugin_update_notice = get_option('softaculous_plugin_update_notice', []);
		$available_update_list = get_site_transient('update_plugins');
		$to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);

		if(empty($available_update_list) || empty($available_update_list->response)){
			return;
		}

		foreach($to_update_plugins as $plugin_path => $plugin_name){
			if(isset($available_update_list->response[$plugin_path])){
				$plugin_update_notice[$plugin_path] = $available_update_list->response[$plugin_path]->new_version;
			}
		}

		update_option('softaculous_plugin_update_notice', $plugin_update_notice);
	}
}
util.php000064400000021614151526414160006243 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Util{
	static function sanitize_get($name, $default = ''){
		if(empty($_GET[$name])){
			return $default;
		}
		
		if(is_array($_GET[$name]) || is_object($_GET[$name])){
			return map_deep(wp_unslash($_GET[$name]), 'sanitize_text_field');
		}

		return sanitize_text_field(wp_unslash($_GET[$name]));
	}

	static function sanitize_post($name, $default = ''){
		if(empty($_POST[$name])){
			return $default;
		}
		
		if(is_array($_POST[$name]) || is_object($_POST[$name])){
			return map_deep(wp_unslash($_POST[$name]), 'sanitize_text_field');
		}

		return sanitize_text_field(wp_unslash($_POST[$name]));
	}

	static function sanitize_request($name, $default = ''){
		if(empty($_REQUEST[$name])){
			return $default;
		}
		
		if(is_array($_REQUEST[$name]) || is_object($_REQUEST[$name])){
			return map_deep(wp_unslash($_REQUEST[$name]), 'sanitize_text_field');
		}

		return sanitize_text_field(wp_unslash($_REQUEST[$name]));
	}
	
	static function sanitize_server($name, $default = ''){
		if(empty($_SERVER[$name])){
			return $default;
		}

		return sanitize_text_field(wp_unslash($_SERVER[$name]));
	}
	
	static function pagespeed_color($score){

		// The structure of this array is 0 => [Stroke Color, Background Color, Text Color]
		$score_color_map = array(
			0 => ['#c00', '#c003', '#c00'], // Red
			50 => ['#fa3', '#ffa50036', '#fa3'],// Orange
			90 => ['#0c6', '#00cc663b', '#080']// Green
		);

		if($score >= 0 && $score < 50){
			return $score_color_map[0];
		}

		if($score >= 50  && $score < 90){
			return $score_color_map[50];
		}

		return $score_color_map[90];
	}
	
	static function url_to_path($url){
		$url = preg_replace('/\?.*/', '', $url); // Removing any query string
		$dir_slug = str_replace(site_url(), '', $url);
		if(defined('SITEPAD')){
			global $sitepad;
			$file_path = $sitepad['path'] . '/' .trim($dir_slug, '/');
		} else {
			$file_path = ABSPATH . trim($dir_slug, '/');
		}
		return wp_normalize_path($file_path);
	}
	
	static function path_to_url($path){
		$path = wp_normalize_path($path);
		if(defined('SITEPAD')){
			global $sitepad;
			$abs_path = wp_normalize_path($sitepad['path']);
		} else {
			$abs_path = wp_normalize_path(ABSPATH);
		}
		$path = str_replace($abs_path, '', $path);
		$url = site_url() . '/' . $path;

		return $url;
	}
	
	static function cache_path($loc = ''){

		if((defined('WP_CLI') && WP_CLI) || empty($_SERVER['HTTP_HOST'])){
			global $blog_id;

			$url = get_option('home');
	
			if(!empty($blog_id) && is_multisite()){
				switch_to_blog($blog_id);
				$url = get_option('home');
				restore_current_blog();
			}

			$url = wp_parse_url($url);			
			$host = $url['host'];

			return trailingslashit(SPEEDYCACHE_CACHE_DIR . '/'.$host.'/'.$loc);
		}
		
		$host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST']));
		return trailingslashit(SPEEDYCACHE_CACHE_DIR . '/'.$host.'/'.$loc);
	}
	
	// Creates a config file based on the URL of the website
	static function set_config_file(){
		global $speedycache;
		
		$export_config['settings']['status'] = !empty($speedycache->options['status']);
		$export_config['settings']['gzip'] = !empty($speedycache->options['gzip']);
		$export_config['settings']['logged_in_user'] = !empty($speedycache->options['logged_in_user']);
		$export_config['settings']['mobile_theme'] = !empty($speedycache->options['mobile_theme']);
		$export_config['settings']['mobile'] = !empty($speedycache->options['mobile']);
		//$export_config['user_agents'] = speedycache_get_excluded_useragent();
		$export_config['excludes'] = get_option('speedycache_exclude', []);

		$config = var_export($export_config, true);

		$url = get_site_url();
		$file = parse_url(untrailingslashit($url));
		$file['path'] = (!empty($file['path'])) ? str_replace( '/', '.', untrailingslashit($file['path'])) : '';
		$config_file_path = WP_CONTENT_DIR .'/speedycache-config/'. strtolower($file['host']) . $file['path'] . '.php';
		
		if(!file_exists(WP_CONTENT_DIR .'/speedycache-config/')){
			if(mkdir(WP_CONTENT_DIR .'/speedycache-config/', 0755, true)){
				touch(WP_CONTENT_DIR .'/speedycache-config/index.html');
				file_put_contents(WP_CONTENT_DIR .'/speedycache-config/.htaccess', 'deny from all');
			}
		}

		$config_temp = file_get_contents(SPEEDYCACHE_DIR . '/assets/config-template.php');
		$config_content = str_replace("'REPLACE_CONFIG'", $config, $config_temp);
		file_put_contents($config_file_path, $config_content);
	}
	
	static function dir_size($dir){
		$size = 0;

		foreach(glob(rtrim($dir, '/').'/*', GLOB_NOSORT) as $file){
			$size += is_file($file) ? filesize($file) : self::dir_size($file);
		}

		return $size;
	}
	
	static function cache_lifespan(){
		global $speedycache;

		$schedule_time = 0;

		if(empty($speedycache->options['purge_interval'])){
			return $schedule_time;
		}

		if(!empty($speedycache->options['purge_enable_exact_time']) && !empty($speedycache->options['purge_exact_time'])){
			$schedule_time = DAY_IN_SECONDS;
		} elseif($speedycache->options['purge_interval_unit'] == 'hours'){
			$schedule_time = HOUR_IN_SECONDS * $speedycache->options['purge_interval'];
		} elseif($speedycache->options['purge_interval_unit'] == 'days'){
			$schedule_time = DAY_IN_SECONDS * $speedycache->options['purge_interval'];
		}

		return (int) $schedule_time;
	}
	
	static function lifespan_cron(){
		global $speedycache;
		
		if(empty($speedycache->options['purge_interval'])){
			return;
		}
		
		if(!empty(wp_next_scheduled('speedycache_purge_cache'))){
			return;
		}

		if(!empty($speedycache->options['purge_enable_exact_time']) && !empty($speedycache->options['purge_exact_time'])){
			// Getting the exact time of the user's timezone by using the offset and strtotime return gtm time.
			$future_timestamp = strtotime('today '.$speedycache->options['purge_exact_time']);
			$offset = get_option('gmt_offset') * HOUR_IN_SECONDS;
			$current_time = time() - $offset;
			$future_timestamp -= $offset;

			if(time() > $future_timestamp){
				$future_timestamp = strtotime('tomorrow '.$speedycache->options['purge_exact_time']);
				$future_timestamp -= $offset;
			}

			$schedule_time = $future_timestamp - time();
			
		} elseif($speedycache->options['purge_interval_unit'] == 'hours'){
			$schedule_time = HOUR_IN_SECONDS * $speedycache->options['purge_interval'];
		} elseif($speedycache->options['purge_interval_unit'] == 'days'){
			$schedule_time = DAY_IN_SECONDS * $speedycache->options['purge_interval'];
		}

		wp_schedule_event(time() + $schedule_time, 'speedycache_expired_cache_schedule', 'speedycache_purge_cache');

	}
	
	static function preload_cron(){
		global $speedycache;
		
		if(empty($speedycache->options['preload_interval']) || empty($speedycache->options['preload'])){
			return;
		}
		
		if(wp_next_scheduled('speedycache_preload')){
			return;
		}

		$schedule_time = HOUR_IN_SECONDS * (int) $speedycache->options['preload_interval'];

		wp_schedule_event(time() + $schedule_time, 'speedycache_preload_cache_schedule', 'speedycache_preload');

	}
	
	static function custom_expiry_cron($schedules){
		
		$cache_interval = self::cache_lifespan();
		if(empty($cache_interval)){
			return $schedules;
		}

		$schedules['speedycache_expired_cache_schedule'] = [
			'interval' => $cache_interval,
			'display' => __('SpeedyCache Cache Lifespan cron', 'speedycache'),
		];

		return $schedules;
	}
	
	static function custom_preload_cron($schedules){
		global $speedycache;

		if(empty($speedycache->options['preload_interval'])){
			return $schedules;
		}
		
		$cache_interval = $speedycache->options['preload_interval'] * HOUR_IN_SECONDS;
		if(empty($cache_interval)){
			return $schedules;
		}

		$schedules['speedycache_preload_cache_schedule'] = [
			'interval' => $cache_interval,
			'display' => __('SpeedyCache Cache Preload cron', 'speedycache'),
		];

		return $schedules;
	}
	
	static function custom_cron($schedules){

		// Every 14 days (Fortnight)
		$schedules['speedycache_fortnight'] = [
			'interval' => 14 * DAY_IN_SECONDS,
			'display' => __('Once Every Fortnight', 'speedycache'),
		];

		// Monthly (approx 30 days)
		$schedules['speedycache_monthly'] = [
			'interval' => 30 * DAY_IN_SECONDS,
			'display' => __('Once Monthly', 'speedycache'),
		];
		
		return $schedules;
	}
	
	// Deletes binaries
	static function delete_cwebp(){
		
		$binary_dir = wp_upload_dir()['basedir'] .'/speedycache-binary';
		
		if(!file_exists($binary_dir)){
			return;
		}

		$binaries = @scandir($binary_dir);
		$binaries = array_diff($binaries, ['.', '..']);
		
		if(empty($binaries)){
			@rmdir($binary_dir);
			return;
		}
		
		foreach($binaries as $binary){
			if(file_exists($binary_dir.'/'.$binary)){
				@unlink($binary_dir.'/'.$binary);
			}
		}
	}
}
cache.php000064400000036235151526414160006336 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

use \SpeedyCache\Util;

class Cache {
	static $cache_file_path = '';
	static $ignored_parameters = ['fbclid', 'utm_id', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_source_platform', 'gclid', 'dclid', 'msclkid', 'ref', 'fbaction_ids', 'fbc', 'fbp', 'clid', 'mc_cid', 'mc_eid', 'hsCtaTracking', 'hsa_cam', 'hsa_grp', 'hsa_mt', 'hsa_src', 'hsa_ad', 'hsa_acc', 'hsa_net', 'hsa_kw'];
	
	static $content = '';

	static function init(){
		global $speedycache;

		if(!defined('SPEEDYCACHE_SERVER_HOST')){
			define('SPEEDYCACHE_SERVER_HOST', Util::sanitize_server('HTTP_HOST'));
		}

		if(!defined('SITEPAD')){
			if(!empty($speedycache->options['dns_prefetch']) && !empty($speedycache->options['dns_urls'])){
				add_filter('wp_resource_hints', '\SpeedyCache\Cache::dns_prefetch_hint', 10, 2);
			}
		}
		
		// Filter for Gravatar cache. We are updating the URL of the gravatar here so the local hosted Gravatar URL will be cached.
		if(!empty($speedycache->options['gravatar_cache'])){
			add_filter('get_avatar_data', '\SpeedyCache\Gravatar::get_avatar_data', 10, 2);
		}

		// Loads Instant Page to improve load page speed by 1%
		if(defined('SPEEDYCACHE_PRO') && !empty($speedycache->options['instant_page'])){
			add_action('wp_enqueue_scripts', '\SpeedyCache\Cache::instant_page');
		}

		if(!empty($speedycache->options['disable_emojis'])){
			add_action('init', '\SpeedyCache\Cache::disable_emojis');
		}
		
		// Optimizes images when a page gets loaded and it finds no image optimized
		if(class_exists('\SpeedyCache\Image') && !empty($speedycache->image['settings']['automatic_optm'])){
			add_filter('the_content', '\SpeedyCache\Image::optimize_on_fly');
		}
		
		// Adds preconnect
		if(class_exists('\SpeedyCache\Enhanced')){
			if(!defined('SITEPAD')){
				if(!empty($speedycache->options['pre_connect']) && !empty($speedycache->options['pre_connect_list'])){
					add_filter('wp_resource_hints', '\SpeedyCache\Enhanced::pre_connect_hint', 10, 2);
				}
			}
		
			// Adds Preload link tag to the head
			if(!empty($speedycache->options['preload_resources'])){
				add_action('wp_head', '\SpeedyCache\Enhanced::preload_resource', 0);
			}
		}

		// Image URL rewrite
		if(class_exists('\SpeedyCache\Image') && !empty($speedycache->image['settings']['url_rewrite'])){
			add_filter('the_content', 'SpeedyCache\Image::rewrite_url_to_webp', 10);
		}

		ob_start('\SpeedyCache\Cache::optimize');
	}

	static function create(){
		global $speedycache;

		$cache_path = self::cache_path();

		if(!file_exists($cache_path)){
			mkdir($cache_path, 0755, true);
		}

		$cache_path .= '/' . self::cache_file_name();
		
		$mobile = '';
		if(strpos($cache_path, 'mobile-cache') !== FALSE){
			$mobile = 'Mobile: ';
		}
		
		$cache_path = wp_normalize_path($cache_path);

		file_put_contents($cache_path, self::$content . "\n<!-- ".esc_html($mobile)."Cache by SpeedyCache https://speedycache.com -->");

		if(function_exists('gzencode') && !empty($speedycache->options['gzip'])){
			$gzidded_content = gzencode(self::$content . "\n<!-- ".esc_html($mobile)."Cache by SpeedyCache https://speedycache.com -->");
			file_put_contents($cache_path . '.gz', $gzidded_content);
		}

		delete_option('speedycache_html_size');
		delete_option('speedycache_assets_size');
	}
	
	static function cache_file_name(){		
		$file_name = 'index';

		if(isset($_COOKIE['wcu_current_currency'])){
			$file_name .= '-'. strtolower(sanitize_file_name($_COOKIE['wcu_current_currency']));
		}

		return $file_name . '.html';
	}
	

	static function cache_path(){
		global $speedycache;
		
		if(!file_exists(SPEEDYCACHE_CACHE_DIR)){
			if(mkdir(SPEEDYCACHE_CACHE_DIR, 0755, true)){
				touch(SPEEDYCACHE_CACHE_DIR . '/index.html');
			}
		}

		$host = $_SERVER['HTTP_HOST'];
		$request_uri = urldecode(esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])));
		$request_uri = preg_replace('/\.{2,}/', '', $request_uri); // Cleaning the path
		$request_uri = remove_query_arg(self::$ignored_parameters, $request_uri); // Cleaning ignored query
		$parsed_uri = wp_parse_url($request_uri);

		$path = SPEEDYCACHE_CACHE_DIR;
		$path .= '/' . $host;

		if(wp_is_mobile() && !empty($speedycache->options['mobile_theme'])){
			$path .= '/mobile-cache';
		} else {
			$path .= '/all';
		}
			
		// Handling WeGlot
		if(function_exists('weglot_get_current_full_url')){
			$weglot_url = weglot_get_current_full_url();
			$weglot_path = parse_url($weglot_url, PHP_URL_PATH);
			
			$path .= $weglot_path;
		} else {
			$path .= $parsed_uri['path'];
		}

		self::$cache_file_path = $path;

		return $path;
	}

	static function can_cache(){
		global $speedycache;
		
		if(empty($speedycache->options['status'])) return false;

		if(empty($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] != 'GET') return false;
		
		if(defined('WP_CLI') && !empty(WP_CLI)) return false;

		if(defined('REST_REQUEST') && !empty(REST_REQUEST)) return false;

		if(function_exists('http_response_code') && (http_response_code() > 309)) return false;
		
		if(preg_match('/\./', $_SERVER['REQUEST_URI'])) return false;
		
		if (defined('SITEPAD')) {
			if (preg_match('/(site-admin|login|wp-register|wp-comments-post|cron|sp-json)/', $_SERVER['REQUEST_URI'])) {
				return false;
			}
		} else {
			if (preg_match('/(wp-(?:admin|login|register|comments-post|cron|json))/', $_SERVER['REQUEST_URI'])) {
				return false;
			}
		}
		
		if(preg_match('/html.*\s(amp|⚡)/', substr(self::$content, 0, 300))) return false;
		
		if(wp_is_mobile() && !empty($speedycache->options['mobile']) && empty($speedycache->options['mobile_theme'])) return false;

		if(is_admin()) return false;

		// Since: 1.2.8 we will only cache the page if user is not logged-in.
		if(is_user_logged_in()) return false;
		
		if(!preg_match( '/<\s*\/\s*html\s*>/i', self::$content)) return false;

		if(is_singular() && post_password_required()) return false;
		
		if(function_exists('is_404') && is_404()) return false;

		if(self::is_excluded()) return false;

		if(function_exists('is_cart') && is_cart()) return false;

		if(function_exists('is_checkout') && is_checkout()) return false;
		
		if(function_exists('is_account_page') && is_account_page()) return false;

		if(!self::can_handle_query()) return false;
	
		return true;
	}

	static function optimize($content){
		global $speedycache;
		
		self::$content = &$content;
		
		$start_time = microtime(TRUE);

		if(!self::can_cache()){
			return self::$content;
		}
		
		self::clean_html();

		// Minify HTML
		if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['minify_html']) && (defined('SPEEDYCACHE_PRO_VERSION') && version_compare(SPEEDYCACHE_PRO_VERSION, '1.2.0', '>='))){
			\SpeedyCache\Enhanced::init();
			\SpeedyCache\Enhanced::minify_html(self::$content);
		}

		// ADD Font Rendering CSS
		if(!empty($speedycache->options['font_rendering'])){
			self::$content = str_replace('</head>', '<style>body{text-rendering: optimizeSpeed;}</style></head>', self::$content);
		}
		
		// Lazy Load HTML elements
		if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['lazy_load_html']) && !empty($speedycache->options['lazy_load_html_elements'])){
			self::$content = \SpeedyCache\Enhanced::lazy_load_html(self::$content);
		}

		if(!empty($speedycache->options['combine_css'])){
			\SpeedyCache\CSS::combine(self::$content);
		}

		if(!empty($speedycache->options['minify_css'])){
			\SpeedyCache\CSS::minify(self::$content);
		}
		
		if(!empty($speedycache->options['combine_js'])){
			\SpeedyCache\JS::combine_head(self::$content);
		}
		
		// if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['combine_js'])){
			// \SpeedyCache\JS::combine_body($content);
		// }
		
		if(!empty($speedycache->options['minify_js'])){
			\SpeedyCache\JS::minify(self::$content);
		}
		
		// Adds Image dimensions to the Image which does not have height or width
		if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['image_dimensions'])){
			self::$content = \SpeedyCache\Enhanced::image_dimensions(self::$content);
		}

		// Google Fonts
		if(class_exists('\SpeedyCache\GoogleFonts') && !empty($speedycache->options['local_gfonts'])){
			\SpeedyCache\GoogleFonts::get($content);
			self::$content = \SpeedyCache\GoogleFonts::replace(self::$content);
			self::$content = \SpeedyCache\GoogleFonts::add_swap(self::$content);
		}

		// Preload Critical Images
		if(class_exists('\SpeedyCache\Enhanced') && !empty($speedycache->options['critical_images'])){
			self::$content = \SpeedyCache\Enhanced::preload_critical_images(self::$content);
		}

		// Delay JS
		if(!empty($speedycache->options['delay_js']) && class_exists('\SpeedyCache\ProOptimizations')){
			\SpeedyCache\ProOptimizations::delay_js(self::$content);
		}
		
		// Defer JS
		if(!empty($speedycache->options['render_blocking']) && class_exists('\SpeedyCache\ProOptimizations')){
			\SpeedyCache\ProOptimizations::defer_js(self::$content);
		}
		
		// IMG Lazy Load
		if(class_exists('\SpeedyCache\ProOptimizations') && !empty($speedycache->options['lazy_load'])){
			\SpeedyCache\ProOptimizations::img_lazy_load(self::$content);
		}
		
		// For other plugins to hook into.
		self::$content = (string) apply_filters('speedycache_content', self::$content);

		// ----- DO NOT DO ANY OPTIMIZATION BELOW THIS ------
		// Unused and Critical CSS
		if(
			!empty($_SERVER['HTTP_HOST']) && 
			!empty($_SERVER['REQUEST_URI']) && 
			!empty($_SERVER['HTTP_USER_AGENT']) && 
			class_exists('\SpeedyCache\ProOptimizations') && 
			speedycache_optserver('HTTP_USER_AGENT') !== 'SpeedyCacheCCSS' && 
			!(defined('SITEPAD'))
		){
			$post_meta = get_post_meta(get_the_ID(), 'speedycache_post_meta', true);
			
			if(!empty($speedycache->options['critical_css']) && empty($post_meta['disable_critical_css'])){
				\SpeedyCache\ProOptimizations::critical_css();
			}
			
			if(empty($post_meta['disable_unused_css']) && !empty($speedycache->options['unused_css'])){
				\SpeedyCache\ProOptimizations::unused_css();
			}
		}
		
		// Rewriting to a CDN
		if(
			!empty($speedycache->cdn) && 
			!empty($speedycache->cdn['enabled']) && 
			!empty($speedycache->cdn['cdn_url']) && 
			!empty($speedycache->cdn['cdn_type']) && 
			$speedycache->cdn['cdn_type'] !== 'cloudflare'
		){
			\SpeedyCache\CDN::rewrite(self::$content);
		}

		self::create();
		$end_time = microtime(TRUE);

		self::$content .= '<!-- Cached by SpeedyCache, it took '.($end_time - $start_time).'s-->';
		self::$content .= '<!-- Refresh to see the cached version -->';
		
		if(file_exists(self::$cache_file_path)){
			header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(self::$cache_file_path)) . ' GMT');
		}
		return self::$content;
	}
	
	static function clean_html(){
		self::$content = str_replace("\r\n", "\n", trim(self::$content));
	}
	
	static function is_excluded(){
		global $speedycache;
		
		$excludes = get_option('speedycache_exclude', []);
		
		if(empty($excludes)){
			return false;
		}

		$is_excluded = false;

		foreach($excludes as $rule){
			switch($rule['type']){
				case 'page':
					$is_excluded = self::is_page_excluded($rule);
					break;

				case 'useragent':
					$is_excluded = self::is_useragent_excluded($rule);
					break;

				case 'cookie':
					$is_excluded = self::is_cookie_excluded($rule);
					break;
			}

			if(!empty($is_excluded)){
				return true;
			}
		}

		return false;
	}
	
	static function can_handle_query(){
		$uri = sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI']));
		$uri = remove_query_arg(self::$ignored_parameters, $uri);
		$parsed_uri = wp_parse_url($uri);

		if(!empty($parsed_uri['query'])){
			return false;
		}

		return true;
	}
	
	static function is_page_excluded($rule){

		if(empty($rule['prefix'])){
			return false;
		}

		if($rule['prefix'] === 'homepage'){
			return is_front_page();
		}
		
		if($rule['prefix'] === 'page'){
			return is_page();
		}

		if($rule['prefix'] === 'post_id' && !empty($rule['content'])){
			$excluded_ids = is_array($rule['content']) ? $rule['content'] : explode(',', $rule['content']);
			return in_array(get_queried_object_id(), $excluded_ids);
		}
		
		// Excludes a page if it has the given shortcode.
		if($rule['prefix'] === 'shortcode' && !empty($rule['content'])){
			if(self::has_shortcode($rule['content'])){
				return true;
			}
		}

		if($rule['prefix'] === 'category'){
			return is_category();
		}
		
		if($rule['prefix'] === 'archive'){
			return is_archive();
		}
		
		if($rule['prefix'] === 'tag'){
			return is_tag();
		}
		
		if($rule['prefix'] === 'attachment'){
			return is_attachment();
		}
		
		if($rule['prefix'] === 'startwith' && !empty($rule['content'])){
			return (bool) preg_match('/^'.preg_quote($rule['content'], '/').'/', trim($_SERVER['REQUEST_URI'], '/'));
		}
		
		if($rule['prefix'] === 'contain' && !empty($rule['content'])){
			return (bool) preg_match('/'.preg_quote($rule['content'], '/').'/', trim($_SERVER['REQUEST_URI'], '/'));
		}
		
		if($rule['prefix'] === 'exact' && !empty($rule['content'])){
			return trim($rule['content'], '/') === trim($_SERVER['REQUEST_URI'], '/');
		}
		
		return false;
	}
	
	static function is_cookie_excluded($rule){
		if(!isset($_SERVER['HTTP_COOKIE'])){
			return false;
		}

		$cookie = sanitize_text_field(wp_unslash($_SERVER['HTTP_COOKIE']));

		return preg_match('/'.preg_quote($rule['content'], '/').'/i', $cookie);
	}
	
	static function is_useragent_excluded($rule){
		return preg_match('/'.preg_quote($rule['content'], '/').'/i', $_SERVER['HTTP_USER_AGENT']);
	}
	
	// Adds DNS prefetch
	static function dns_prefetch_hint($urls, $relation_type){
		global $speedycache;

		if($relation_type !== 'dns-prefetch'){
			return $urls;
		}

		foreach($speedycache->options['dns_urls'] as $url) {
			if(!empty($url)){
				$urls[] = $url;
			}
		}

		return $urls;
	}
	
	// Depricated since 1.2.0 do not use it
	// Just to prevent site from breaking
	static function create_dir($path, $content, $type = ''){
	}
	
	
	static function disable_emojis(){
		add_filter('emoji_svg_url', '__return_false');
		remove_action('wp_head', 'print_emoji_detection_script', 7);
		remove_action('admin_print_scripts', 'print_emoji_detection_script');
		remove_action('wp_print_styles', 'print_emoji_styles');
		remove_action('admin_print_styles', 'print_emoji_styles');
		remove_filter('the_content_feed', 'wp_staticize_emoji');
		remove_filter('comment_text_rss', 'wp_staticize_emoji'); 
		remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
	}
	
	static function instant_page(){
		wp_enqueue_script('speedycache_instant_page', SPEEDYCACHE_PRO_URL . '/assets/js/instantpage.js', array(), SPEEDYCACHE_PRO_VERSION, ['strategy' => 'defer', 'in_footer' => true]);
	}
	
	/*
	* @param string $shortcode shortcode tag name.
	* @return bool.
	*/
	static function has_shortcode($shortcode){
		global $post;

		return \has_shortcode($post->post_content, $shortcode);
	}
}
htaccess.php000064400000020731151526414160007062 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Htaccess {

	static function init(){

		if(!empty($_SERVER['SERVER_SOFTWARE'])){
			$server_name = sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE']));

			if(!empty($server_name) && (preg_match('/nginx/i', $server_name) || preg_match('/iis/i', $server_name))){
				return;
			}
		}

		if(defined('SITEPAD')){
			global $sitepad;
			$htaccess_file = $sitepad['path'] . '/.htaccess';
		}else{
			$htaccess_file = ABSPATH . '/.htaccess';
		}
		
		if(!file_exists($htaccess_file)){
			return false;
		}

		if(!is_writable($htaccess_file)){
			return;
		}

		$htaccess_content = file_get_contents($htaccess_file);

		$htaccess_rules = '';
		self::headers($htaccess_rules);
		self::gzip($htaccess_rules);
		self::browser_cache($htaccess_rules);
		self::webp($htaccess_rules);
		self::serving_rules($htaccess_rules);

		// TODO: Need to add modified time here.
		// Cleaning stuff
		$htaccess_content = preg_replace("/#\s?BEGIN\s?LBCspeedycache.*?#\s?END\s?LBCspeedycache/s", '', $htaccess_content);
		$htaccess_content = preg_replace("/#\s?BEGIN\s?WEBPspeedycache.*?#\s?END\s?WEBPspeedycache/s", '', $htaccess_content);
		$htaccess_content = preg_replace("/#\s?BEGIN\s?Gzipspeedycache.*?#\s?END\s?Gzipspeedycache/s", '', $htaccess_content);
		$htaccess_content = preg_replace("/#\s?BEGIN\s?SpeedyCacheheaders.*?#\s?END\s?SpeedyCacheheaders/s", '', $htaccess_content);
		$htaccess_content = preg_replace("/#\s?BEGIN\s?speedycache.*?#\s?END\s?speedycache/s", '', $htaccess_content);
		$htaccess_content = $htaccess_rules ."\n" . trim($htaccess_content);

		file_put_contents($htaccess_file, $htaccess_content);

	}
	
	static function serving_rules(&$htaccess_rules){
		global $speedycache;
		$base_cache_path = defined('SITEPAD') ? 'sitepad-data' : 'wp-content';
		$platform_excludes = defined('SITEPAD') ?
		'RewriteCond %{REQUEST_URI} !^/(site-admin|login|wp-register|wp-comments-post|cron|sp-json)/ [NC]' :
		'RewriteCond %{REQUEST_URI} !^/(wp-(?:admin|login|register|comments-post|cron|json))/ [NC]';

		$htaccess_rules .= '# BEGIN speedycache
<IfModule mod_rewrite.c>
RewriteEngine On';
		if(!defined('SITEPAD')){
			$htaccess_rules .= "\n".'RewriteBase /';
		}

		if(!empty($speedycache->options['mobile']) && !empty($speedycache->options['mobile_theme'])){
			$htaccess_rules .= '
	RewriteCond %{REQUEST_METHOD} GET
	RewriteCond %{HTTP_USER_AGENT} !(Mediatoolkitbot|facebookexternalhit|SpeedyCacheCCSS)
	RewriteCond %{HTTP_USER_AGENT} (Mobile|Android|Silk\/|Kindle|Opera\sMini|BlackBerry|Opera\sMobi) [NC]
	RewriteCond %{QUERY_STRING} =""
	'.self::cookie_excludes().'
	RewriteCond %{REQUEST_URI} !(\/){2}$
	'.$platform_excludes.'
	RewriteCond %{DOCUMENT_ROOT}/'.$base_cache_path.'/cache/speedycache/%{HTTP_HOST}/mobile-cache%{REQUEST_URI}/index.html -f
	RewriteRule ^(.*) /'.$base_cache_path.'/cache/speedycache/%{HTTP_HOST}/mobile-cache%{REQUEST_URI}/index.html [L]'."\n";
		}

$htaccess_rules .= '
	RewriteCond %{REQUEST_METHOD} GET
	RewriteCond %{HTTP_USER_AGENT} !(Mediatoolkitbot|facebookexternalhit|SpeedyCacheCCSS)
	RewriteCond %{QUERY_STRING} =""
	'.self::cookie_excludes()."\n";

	if(!empty($speedycache->options['mobile'])){
		$htaccess_rules .= '
	RewriteCond %{HTTP_USER_AGENT} !(Mobile|Android|Silk\/|Kindle|Opera\sMini|BlackBerry|Opera\sMobi) [NC]' . "\n";
	}

	$htaccess_rules .= '
	RewriteCond %{REQUEST_URI} !(\/){2}$
	'.$platform_excludes.'
	RewriteCond %{DOCUMENT_ROOT}/'.$base_cache_path.'/cache/speedycache/%{HTTP_HOST}/all%{REQUEST_URI}/index.html -f
	RewriteRule ^(.*) /'.$base_cache_path.'/cache/speedycache/%{HTTP_HOST}/all%{REQUEST_URI}/index.html [L]
</IfModule>
# END speedycache' . PHP_EOL;
	}
	
	static function browser_cache(&$htaccess_rules){
		global $speedycache;

		if(empty($speedycache->options['lbc'])){
			return;
		}

		$htaccess_rules .= '# BEGIN LBCspeedycache
<IfModule mod_expires.c>
	ExpiresActive on
	ExpiresDefault A0
	ExpiresByType text/css A31536000
	ExpiresByType text/javascript A31536000
	ExpiresByType font/ttf A31536000
	ExpiresByType font/otf A31536000
	ExpiresByType font/woff A31536000
	ExpiresByType font/woff2 A31536000
	ExpiresByType image/jpg A31536000
	ExpiresByType image/jpeg A31536000
	ExpiresByType image/png A31536000
	ExpiresByType image/gif A31536000
	ExpiresByType image/webp A31536000
	ExpiresByType image/x-icon A31536000
	ExpiresByType image/svg+xml A31536000
	ExpiresByType image/vnd.microsoft.icon A31536000
	ExpiresByType video/ogg A31536000
	ExpiresByType video/mp4 A31536000
	ExpiresByType video/webm A31536000
	ExpiresByType audio/ogg A31536000
	ExpiresByType application/pdf A31536000
	ExpiresByType application/javascript A31536000
	ExpiresByType application/x-javascript A31536000
	ExpiresByType application/x-font-ttf A31536000
	ExpiresByType application/x-font-woff A31536000
	ExpiresByType application/font-woff A31536000
	ExpiresByType application/font-woff2 A31536000
	ExpiresByType application/vnd.ms-fontobject A31536000
</IfModule>
# END LBCspeedycache' . PHP_EOL;
	}

	static function webp(&$htaccess_rules){
		$htaccess_rules .= '# BEGIN WEBPspeedycache
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteCond %{HTTP_ACCEPT} image/webp
	RewriteCond %{REQUEST_FILENAME} \.(jpe?g|png|gif)$
	RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
	RewriteRule ^(.+)\.(jpe?g|png|gif)$ $1.webp [T=image/webp,L]
</IfModule>
<IfModule mod_headers.c>
  Header append Vary Accept env=REDIRECT_accept
</IfModule>
AddType image/webp .webp
# END WEBPspeedycache' . PHP_EOL;
	}
	
	static function gzip(&$htaccess_rules){
		global $speedycache;

		if(empty($speedycache->options['gzip'])){
			return;
		}

		$htaccess_rules .= '# BEGIN Gzipspeedycache
<IfModule mod_deflate.c>
	AddOutputFilterByType DEFLATE font/opentype
	AddOutputFilterByType DEFLATE font/otf
	AddOutputFilterByType DEFLATE font/ttf
	AddOutputFilterByType DEFLATE font/woff
	AddOutputFilterByType DEFLATE font/woff2
	AddOutputFilterByType DEFLATE text/js
	AddOutputFilterByType DEFLATE text/css
	AddOutputFilterByType DEFLATE text/html
	AddOutputFilterByType DEFLATE text/javascript
	AddOutputFilterByType DEFLATE text/plain
	AddOutputFilterByType DEFLATE text/xml
	AddOutputFilterByType DEFLATE image/svg+xml
	AddOutputFilterByType DEFLATE image/x-icon
	AddOutputFilterByType DEFLATE application/javascript
	AddOutputFilterByType DEFLATE application/x-javascript
	AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
	AddOutputFilterByType DEFLATE application/x-font
	AddOutputFilterByType DEFLATE application/x-font-opentype
	AddOutputFilterByType DEFLATE application/x-font-otf
	AddOutputFilterByType DEFLATE application/x-font-truetype
	AddOutputFilterByType DEFLATE application/x-font-ttf
	AddOutputFilterByType DEFLATE application/font-woff2
	AddOutputFilterByType DEFLATE application/xhtml+xml
	AddOutputFilterByType DEFLATE application/xml
	AddOutputFilterByType DEFLATE application/rss+xml
</IfModule>
# END Gzipspeedycache'. PHP_EOL;
	}
	
	static function headers(&$htaccess_rules){
		$url = site_url();
		$parsed_url = wp_parse_url($url);

		$htaccess_rules .= '# BEGIN SpeedyCacheheaders
FileETag None
<IfModule mod_headers.c>
	Header unset ETag
</IfModule>
<FilesMatch "\.(html)$">
<IfModule mod_headers.c>
	Header set x-speedycache-source "Server"
	Header set Cache-Tag "'.$parsed_url['host'].'"
	Header set CDN-Cache-Control "max-age=1296000"
	Header set Cache-Control "public"
	Header unset Pragma
	Header unset Last-Modified
</IfModule>
</FilesMatch>

<FilesMatch "\.(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
	<IfModule mod_headers.c>
		Header unset Pragma
		Header set Cache-Control "public"
	</IfModule>
</FilesMatch>
# END SpeedyCacheheaders'. PHP_EOL;
	}
	
	static function cookie_excludes(){
		$cookies = [];

		$cookies[] = 'comment_author_';
		$cookies[] = 'wordpress_logged_in_';
		if(!defined('SITEPAD')){
			if(is_plugin_active('woo-currency/wcu.php')){
				$cookies[] = 'wcu_current_currency';
			}
		}
		$cookies_to_exclude = implode('|', $cookies);
		$cookies_to_exclude = preg_replace("/\s/", "\s", $cookies_to_exclude);

		return 'RewriteCond %{HTTP:Cookie} !('.$cookies_to_exclude.')';
	}

}
advanced-cache.php000064400000014744151526414160010102 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

if(!defined('ABSPATH')) exit;

// Check request method is Head or get 
if(!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET'){
	return;
}

if(defined('WP_INSTALLING') && WP_INSTALLING){
	return;
}

if(defined('WP_CLI') && WP_CLI){
	return;
}

if(empty($_SERVER['REQUEST_URI']) || empty($_SERVER['HTTP_HOST']) || empty($_SERVER['HTTP_USER_AGENT'])){
    return false;
}

if(preg_match('/(\/){2}$/', $_SERVER['REQUEST_URI'])){
	return false;
}

function speedycache_ac_serve_cache(){

	$ignored_parameters = ['fbclid', 'utm_id', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_source_platform', 'gclid', 'dclid', 'msclkid', 'ref', 'fbaction_ids', 'fbc', 'fbp', 'clid', 'mc_cid', 'mc_eid', 'hsCtaTracking', 'hsa_cam', 'hsa_grp', 'hsa_mt', 'hsa_src', 'hsa_ad', 'hsa_acc', 'hsa_net', 'hsa_kw', 'test_speedycache'];

	$uri = '';
	$parsed_uri = [];
	$uri = $_SERVER['REQUEST_URI'];
	$uri = urldecode($uri); // Users use other languages to write as well
	$uri = preg_replace('/\.{2,}/', '', $uri); // Cleaning the path

	$parsed_uri = parse_url($uri);
	if(!empty($parsed_uri) && !empty($parsed_uri['query'])){
		parse_str($parsed_uri['query'], $parsed_query);

		foreach($parsed_query as $query => $value){
			if(in_array($query, $ignored_parameters)){
				unset($parsed_query[$query]);
				continue;
			}
		}

		$uri = $parsed_uri['path'] . (!empty($parsed_query) ? '?'.http_build_query($parsed_query) : '');
	}
	
	// We dont know if the site is a /directory based so we just hit and try
	$site_dir = '';

	$path = '';
	if(!empty($parsed_uri['path'])){
		$path = trim($parsed_uri['path'], '/');
	}

	if(strpos($path, '/') !== FALSE){
		$parsed_path = explode('/', $path);
		$site_dir = $parsed_path[0];
	} elseif(!empty($path)){
		$site_dir = $path;
	}

	$config_file = WP_CONTENT_DIR . '/speedycache-config/' . basename($_SERVER['HTTP_HOST']) . '.php';

	if(!file_exists($config_file)){
		$config_file = WP_CONTENT_DIR . '/speedycache-config/' . basename($_SERVER['HTTP_HOST']) . '.'. $site_dir . '.php';
		if(!file_exists($config_file)){
			return;
		}
	}

	if(!file_exists($config_file)){
		return;
	}

	// Accessing the config file
	include_once $config_file;
	
	if(empty($speedycache_ac_config) || !is_array($speedycache_ac_config)){
		return;
	}

	if(empty($speedycache_ac_config['settings']['status'])){
		return;
	}
	
	// Exclude pages|useragent|cookie
	if(speedycache_ac_excludes($speedycache_ac_config)){
		return;
	}

	if(!empty($speedycache_ac_config['user_agents']) && preg_match('/'.preg_quote($speedycache_ac_config['user_agents']).'/', $_SERVER['HTTP_USER_AGENT'])){
		return;
	}
	
	if(empty($speedycache_ac_config['settings']['logged_in_user']) && preg_grep('/^wordpress_logged_in_/i', array_keys($_COOKIE))){
		return false;
	}

	// check comment author
	if(preg_grep('/comment_author_/i', array_keys($_COOKIE))){
		return false;
	}

	$cache_path = WP_CONTENT_DIR.'/cache/speedycache/' . basename($_SERVER['HTTP_HOST']);

	// For the test cache
	if(isset($_GET['test_speedycache'])){
		$cache_path = '/test'. $uri;
	} else if(!empty($speedycache_ac_config['settings']['mobile']) && preg_match('/Mobile|Android|Silk\/|Kindle|BlackBerry|Opera (Mini|Mobi)/i', $_SERVER['HTTP_USER_AGENT'])) {
		// Check for Mobile
		if(!empty($speedycache_ac_config['settings']['mobile_theme'])){
			$cache_path .= '/mobile-cache' . $uri;
		} else {
			return; // If just mobile is enabled then we don't want to show desktop verison of cache on mobile.
		}
	} else {
		// get path of file
		$cache_path .= '/all'. $uri;
	}
	
	$file_name = 'index';
	if(isset($_COOKIE['wcu_current_currency'])){
		$file_name .= '-' . strtolower($_COOKIE['wcu_current_currency']);
		$file_name = preg_replace('/\.{2,}/', '', $file_name); // Cleaning the path
	}
	$file_name .= '.html';

	//check file extension
	$serving_gz = '';
	if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE && !empty($speedycache_ac_config['settings']['gzip']) && @file_exists($cache_path . '/'. $file_name.'.gz')){
		$serving_gz = '.gz';
		
		// We do not want output compression to be enabled if we are gzipping the page.
		if(function_exists('ini_set')){
			ini_set('zlib.output_compression', 0);
		}

		header('Content-Encoding: gzip');
	}

	if(!file_exists($cache_path . '/'.$file_name . $serving_gz)){
		$serving_gz = '';
	}
	
	if(!file_exists($cache_path . '/'.$file_name . $serving_gz)){
		return;
	}

	if(!headers_sent()){
		header('x-speedycache-source: PHP');
	}

	$cache_created_at = filemtime($cache_path. '/'.$file_name . $serving_gz);
	header('Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $cache_created_at) . ' GMT');

	$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : 0;

	if($if_modified_since === $cache_created_at){
		header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
		header('Cache-Control: no-cache, must-revalidate');
		header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
		exit();
	}

	readfile($cache_path. '/'.$file_name . $serving_gz);
	exit();
}

function speedycache_ac_excludes($excludes){
	if(empty($excludes) || !is_array($excludes)){
		return false;
	}

	$preg_match_rule = '';
	$request_url = !empty($_SERVER['REQUEST_URI']) ? urldecode(trim($_SERVER['REQUEST_URI'], '/')) : '';

	foreach($excludes as $key => $value){
		$value['type'] = !empty($value['type']) ? $value['type'] : 'page';

		if(!empty($value['prefix']) && $value['type'] == 'page'){
			$value['content'] = trim($value['content']);
			$value['content'] = trim($value['content'], '/');
			
			if($value['prefix'] == 'exact' && strtolower($value['content']) == strtolower($request_url)){
				return true;
			}else{
				$preg_match_rule = preg_quote($value['content'], '/');

				if($preg_match_rule){
					if(preg_match('/'.$preg_match_rule.'/i', $request_url)){
						return true;
					}
				}
			}
		}else if($value['type'] == 'useragent'){
			if(preg_match('/'.preg_quote($value['content'], '/').'/i', $_SERVER['HTTP_USER_AGENT'])){
				return true;
			}
		}else if($value['type'] == 'cookie'){
			if(isset($_SERVER['HTTP_COOKIE'])){
				if(preg_match('/'.preg_quote($value['content'], '/').'/i', $_SERVER['HTTP_COOKIE'])){
					return true;
				}
			}
		}
	}
}

speedycache_ac_serve_cache();delete.php000064400000033135151526414160006531 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT');
}

use \SpeedyCache\Util;

class Delete{
	
	static $cache_lifespan = 0;

	static function run($actions){
		global $speedycache;
		
		// Even if the actions are empty, the cache will be deleted.
		self::all_cache();
		self::purge_varnish();
		\SpeedyCache\CDN::purge();
		delete_option('speedycache_html_size');
		delete_option('speedycache_assets_size');

		if(empty($actions)){
			return;
		}
		
		if(!empty($actions['minified'])){
			self::minified();
		}
		
		if(!empty($actions['font'])){
			self::local_fonts();
		}
		
		if(!empty($actions['gravatars'])){
			self::gravatar();
		}
		
		if(!empty($actions['domain'])){
			self::all_for_domain();
		}
		
		if(!empty($actions['preload'])){
			if(!empty($speedycache->options['preload'])){
				\SpeedyCache\Preload::build_preload_list();
			}
		}
	}
	
	/**
	 * Deletes cache of a single page
	 * @param int $post_id
	 */
	static function cache($post_id = false){
		global $speedycache;

		if(!isset($post_id) || $post_id === FALSE || !is_numeric($post_id)){
			return;
		}

		$link = get_permalink($post_id);

		// If its 0 then it's a homepage
		if($post_id == 0){
			$link = home_url();
		}

		if(empty($link)){
			return;
		}

		self::url($link);

		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
		
		if(!empty($speedycache->options['preload'])){
			\SpeedyCache\Preload::url($link);
		}

		delete_option('speedycache_html_size');
		delete_option('speedycache_assets_size');
	}

	/**
	* Deletes cache of a URL
	* Parses and converts a URL to cache path and purges it
	* @param array|string $urls
	*/
	static function url($urls){
		global $speedycache;

		$urls = (array) $urls;
		$cache_paths = [];

		foreach($urls as $url){
			$parsed_url = wp_parse_url($url);
			$path = !empty($parsed_url['path']) ? $parsed_url['path'] : '';
			
			// Path to be used in glob so that we can get all the variations of file created like for language or currency
			$file = (empty($path) || $path == '/') ? 'index*html' : trim($path, '/') . '/index*html';

			// Cache path for desktop cache
			$all_path = glob(Util::cache_path('all') . $file);
			$gz_path = glob(Util::cache_path('all') . $file .'.gz');
			
			$all_path = array_merge(
				is_array($all_path) ? $all_path : [], 
				is_array($gz_path) ? $gz_path : []
			);

			if(!empty($all_path)){
				$cache_paths = array_merge($cache_paths, $all_path);
			}

			// Cache path for Mobile cache
			if(!empty($speedycache->options['mobile_theme'])){
				$mobile_path = glob(Util::cache_path('mobile-cache') . $file);

				if(!empty($mobile_path)){
					$cache_paths = array_merge($cache_paths, $mobile_path);
				}
			}
		}

		foreach($cache_paths as $cache_path){
			if(!file_exists($cache_path)){
				continue;
			}

			if(is_dir($cache_path)){
				self::rmdir($cache_path);
				continue;
			}

			unlink($cache_path);
		}
	}

	// Delete cache of whole site
	static function all_cache(){

		// Our cache is saved in 2 file, /all and /mobile-cache
		// We also need to delete Critical CSS too as it gets injected in the HTML
		$deletable_dirs = ['all', 'mobile-cache', 'critical-css'];
		
		foreach($deletable_dirs as $dir){
			$path = Util::cache_path($dir);
			self::rmdir($path);
		}

		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
	}

	// Delete minified and Critical css content.
	static function minified(){
		$assets_cache_path = Util::cache_path('assets');

		if(!file_exists($assets_cache_path)){
			return;
		}

		self::rmdir($assets_cache_path);

		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
	}

	// Delete local fonts
	static function local_fonts(){
		$fonts_path = Util::cache_path('fonts');

		if(!file_exists($fonts_path)){
			return;
		}

		self::rmdir($fonts_path);
		
		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
	}

	static function gravatar(){
		$gravatar_path = Util::cache_path('gravatars');
		
		if(!file_exists($gravatar_path)){
			return;
		}

		self::rmdir($gravatar_path);
		
		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
	}
	
	// Delete everything of the current domain, like minfied, cache, gravatar and fonts.
	static function all_for_domain(){
		
	}

	static function rmdir($dir){

		if(!file_exists($dir)){
			return;
		}

		$files = array_diff(scandir($dir), ['..', '.']);

		foreach($files as $file){
			if(is_dir($dir.'/'.$file)){
				self::rmdir($dir.'/'.$file);
				continue;
			}

			unlink($dir.'/'.$file);
		}

		rmdir($dir);
	}
	
	static function purge_varnish(){
		global $speedycache;

		if(empty($speedycache->options['purge_varnish'])){
			return;
		}

		$server = !empty($speedycache->options['varniship']) ? $speedycache->options['varniship'] : '127.0.0.1';
		
		
		$url = home_url();
		$url = parse_url($url);

		if($url == FALSE){
			return;
		}
		
		$sslverify = ($url['scheme'] === 'https') ? true : false;
		$request_url = $url['scheme'] .'://'. $server . '/.*';

		$request_args = array(
			'method'    => 'PURGE',
			'headers'   => array(
				'Host'       => $url['host'],
			),
			'sslverify' => $sslverify,
		);

		$res = wp_remote_request($request_url, $request_args);

		if(is_wp_error($res)){
			$msg = $res->get_error_message();
			return array($msg, 'error');
		}

		if(is_array($res) && !empty($res['response']['code']) && '200' != $res['response']['code']){
			$msg = 'Something Went Wrong Unable to Purge Varnish';
			
			if(empty($res['response']['code']) && '501' == $res['response']['code']){
				$msg = 'Your server dosen\'t allows PURGE request';

				if(!empty($res['headers']['allow'])){
					$msg .= 'The accepted HTTP methods are' . $res['headers']['allow'];
				}
				
				$msg = __('Please contact your hosting provider if, Varnish is enabled and still getting this error', 'speedycache');
			}
			
			return array($msg, 'error');
		}
		
		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
		
		return array(__('Purged Varnish Cache Succesfully', 'speedycache'), 'success');
	}

	static function expired_cache(){
		global $speedycache;

		self::$cache_lifespan = Util::cache_lifespan();
		
		// We don't want to clean cache if cache is disabled
		if(empty($speedycache->options['status']) || empty(self::$cache_lifespan)){
			wp_clear_scheduled_hook('speedycache_purge_cache');
			return;
		}

		$cache_path = [];
		$cache_path[] = Util::cache_path('all');
		$cache_path[] = Util::cache_path('mobile-cache');
		
		foreach($cache_path as $path){		
			if(!file_exists($path)){
				continue;
			}

			self::rec_clean_expired($path);
		}

		// Assets are deleted only if the lifetime is more than 10 hours,  
		// because only then is the entire cache deleted.  
		// Cached assets may be used on multiple pages,  
		// so we must ensure they are not deleted unless all cached pages are removed.
		if(self::$cache_lifespan > 10 * HOUR_IN_SECONDS){
			self::minified();

			if(!empty($speedycache->options['auto_purge_fonts'])){
				self::local_fonts();
			}

			if(!empty($speedycache->options['auto_purge_gravatar'])){
				self::gravatar();
			}
		}
		
		// We will delete it even if the cache does not gets deleted
		delete_option('speedycache_html_size');
		delete_option('speedycache_assets_size');
		
		if(class_exists('\SpeedyCache\Logs')){
			\SpeedyCache\Logs::log('delete');
			\SpeedyCache\Logs::action();
		}
		
		// Preload the cached
		if(self::$cache_lifespan > 10 * HOUR_IN_SECONDS && !empty($speedycache->options['preload'])){
			\SpeedyCache\Preload::build_preload_list();
		}
	}
	
	// Recursively deletes expired cache
	static function rec_clean_expired($path){
		$files = array_diff(scandir($path), array('..', '.'));

		if(empty($files)){
			return;
		}

		foreach($files as $file){
			$file_path = $path . '/'. $file;

			if(is_dir($file_path)){
				self::rec_clean_expired($file_path);
				continue;
			}

			// We will delete all cache if the lifespan is greater than 10 hours to prevent nonce issues,
			// We could delete all the cache for lifespan above 10 hrs, but for larger sites deleting 
			// everything colud be a overhead.
			if((self::$cache_lifespan >= 10 * HOUR_IN_SECONDS) || ((filemtime($file_path) + self::$cache_lifespan) < time())){
				unlink($file_path);
			}
		}
	}

	// Deletes the cache of the post whose status got changed,
	// only deletes when the post transitions in our out of published mode
	static function on_status_change($new_status, $old_status, $post){
		global $speedycache;

		if($old_status == $new_status && $old_status !== 'publish') return;

		if($old_status !== 'publish' && $new_status !== 'publish'){
			return;
		}

		if(empty($speedycache->options['status'])){
			return;
		}

		if(!empty(wp_is_post_revision($post->ID))){
			return;
		}

		// Current post should not be deleted when its anything other than publish,
		// As in some states its URL changes to ?page_id=
		if($new_status == 'publish'){
			self::cache($post->ID);
		}

		// Deleting the cache of home page and blog page
		$home_page_id = get_option('page_on_front');
		self::cache($home_page_id);

		// For some sites home page and blog page could be same
		$blog_page_id = get_option('page_for_posts');
		if($home_page_id !== $blog_page_id){
			self::cache($blog_page_id);
		}

		// Deleting the author page cache
		$author_page_url = get_author_posts_url($post->post_author);
		self::url($author_page_url);

		// Deleting cache of related terms
		self::terms($post->ID);
		
		// Delete shop page when product status changes.
		if(function_exists('wc_get_page_id')){
			$shop_page_id = wc_get_page_id('shop');
			
			if($home_page_id !== $shop_page_id){
				self::cache($shop_page_id);
			}
		}

		// This is used to delete post which may have the current post as the related post / product in them
		self::adjacent_posts_urls();
	}

	// Deletes cache of the page where a comments status got change.
	static function on_comment_status($new_status, $old_status, $comment){
		global $speedycache;

		if($old_status == $new_status && $old_status !== 'approved') return;

		if($old_status !== 'approved' && $new_status !== 'approved'){
			return;
		}

		if(empty($speedycache->options['status'])){
			return;
		}

		self::cache($comment->comment_parent);
		
	}

	static function terms($post_id){
		global $speedycache;
		
		if(empty($post_id) || !is_numeric($post_id)){
			return;
		}

		$post_type = get_post_type($post_id);
    
		if(empty($post_type)){
			return;
		}

		// Get all taxonomies for the post type
		$taxonomies = get_object_taxonomies($post_type, 'objects');

		// Filter to keep only public taxonomies
		$public_taxonomies = [];
		foreach($taxonomies as $taxonomy){
			if($taxonomy->public){
				$public_taxonomies[] = $taxonomy->name;
			}
		}

		if(empty($public_taxonomies)){
			return;
		}

		$terms = wp_get_post_terms($post_id, $public_taxonomies);

		if(empty($terms) || is_wp_error($terms)){
			return;
		}

		$deletable_links = [];
		foreach($terms as $term){
			$link = get_term_link($term->term_id);
			
			if(is_wp_error($link) || empty($link)){
				continue;
			}

			$deletable_links[] = $link;

			$ancestors = get_ancestors($term->term_id, $term->taxonomy);
			if(!empty($ancestors)){
				foreach($ancestors as $ancestor){
					$ancestor_link = get_term_link($ancestor);

					if(is_wp_error($ancestor_link) || empty($ancestor_link)){
						continue;
					}

					$deletable_links[] = $ancestor_link;
				}
			}
		}

		if(empty($deletable_links)){
			return;
		}
		
		$deletable_links = array_unique($deletable_links);
		
		self::url($deletable_links);
		
		if(!empty($speedycache->options['preload'])){
			\SpeedyCache\Preload::url($deletable_links);
		}
	}
	
	static function adjacent_posts_urls(){
		$post_urls = [];
		
		$prev_post = get_adjacent_post();
		$prev_post_term = get_adjacent_post(true, '');
		$next_post = get_adjacent_post(false, '', true);
		$next_post_term = get_adjacent_post(true, '', true);
		
		if(!empty($prev_post)){
			$post_urls[] = get_permalink($prev_post);
		}

		if(!empty($prev_post_term)){
			$post_urls[] = get_permalink($prev_post_term);
		}
		
		if(!empty($next_post)){
			$post_urls[] = get_permalink($next_post);
		}
		
		if(!empty($next_post_term)){
			$post_urls[] = get_permalink($next_post_term);
		}

		if(!empty($post_urls)){
			self::url($post_urls);
		}
	}

	// Deletes cache of product page and its related pages when a order is made
	static function order($order_id){
		global $speedycache;

		if(empty($speedycache->options['status'])){
			return;
		}

		if(!function_exists('wc_get_order')){
			return;
		}

		$order = wc_get_order($order_id);
		$items = $order->get_items();

		foreach($items as $item){
			$product_id = $item->get_product_id();
			
			if(empty($product_id)){
				continue;
			}

			self::cache($product_id);
			
			$categories = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids'));

			foreach($categories as $category){
				self::cache($category);
			}
		}

		$shop_page_id = wc_get_page_id('shop');
		self::cache($shop_page_id);
	}
}
css.php000064400000014334151526414160006057 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

use \SpeedyCache\lib\Minify;
use \SpeedyCache\Util;

class CSS{
	
	static function minify(&$content){
		global $speedycache;
		
		if(empty($content)){
			return;
		}

		preg_match_all('/<link\s+([^>]+[\s"\'])?href\s*=\s*[\'"]\s*?(?<url>[^\'"]+\.css(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>/Umsi', $content, $tags, PREG_SET_ORDER);

		if(empty($tags)){
			return;
		}

		if(empty($_SERVER['HTTP_HOST'])){
			return;
		}

		$site_host = str_replace('www.', '', sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])));
		$site_url = site_url();

		foreach($tags as $tag){

			if(empty($tag['url'])){
				continue;
			}

			$url = $tag['url'];
			
			if(self::is_excluded($url)) continue;

			// We don't want to minify already minified css
			if(strpos($url, '.min.css') !== FALSE){
				continue;
			}

			// We wont process any css that is not present on this WordPress install
			if(strpos($url, $site_host) === FALSE){
				continue;
			}

			$file_path = Util::url_to_path($url);

			if(!file_exists($file_path)){
				continue;
			}

			$file_name = self::file_name($file_path);
			$asset_path = Util::cache_path('assets');
			if(!is_dir($asset_path)){
				mkdir($asset_path, 0755, true);
				touch($asset_path . 'index.html');
			}

			$minified_path = $asset_path.$file_name;

			// If we already have a minified file then we dont need to process it again.
			if(!file_exists($minified_path)){
				$minified = new Minify\CSS($file_path);
				$minified = $minified->minify();

				$minified = self::fix_relative_path($minified, $url);
				file_put_contents($minified_path, $minified);
			}

			$minified_url = Util::path_to_url($minified_path);
			$content = str_replace($tag['url'], $minified_url, $content);
			
			// TODO: check if there is a preload.
		}
		
	}

	static function file_name($path){
		$file_hash = md5_file($path);
		$file_name = substr($file_hash, 0, 16) . '-' . basename($path);

		return $file_name;
	}
	
	static function combine(&$content){
		if(empty($content)){
			return;
		}

		preg_match_all('/<link\s+([^>]+[\s"\'])?href\s*=\s*[\'"]\s*?(?<url>[^\'"]+\.css(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>/Umsi', $content, $tags, PREG_SET_ORDER);
		
		if(empty($tags)){
			return;
		}

		if(empty($_SERVER['HTTP_HOST'])){
			return;
		}

		$site_host = str_replace('www.', '', sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])));
		$site_url = site_url();

		$combined_css = '';
		$prev_tag = '';
		
		$tags = array_reverse($tags);

		foreach($tags as $tag){

			if(empty($tag['url'])){
				continue;
			}

			$url = $tag['url'];
			
			if(self::is_excluded($url)) continue;

			// We wont process any css that is not present on this WordPress install
			if(strpos($url, $site_host) === FALSE){
				continue;
			}

			$file_path = Util::url_to_path($url);

			if(!file_exists($file_path) || !is_readable($file_path)){
				continue;
			}
			
			$new_css = file_get_contents($file_path);
			$new_css = self::fix_relative_path($new_css, $url);

			$combined_css = $new_css . "\n" . $combined_css;

			// Removing the CSS which has already been combined, as we will add the combined file at the top after title.
			if(!empty($prev_tag)){
				$content = str_replace($prev_tag, '', $content);
			}

			// We remove the previous tag, in current iteration, so at last we have a tag to replace wirh the combined script.
			$prev_tag = $tag[0];
			
			//TODO: Need to remove any preload added by any plugin or a theme.
		}

		if(empty($combined_css)){
			return;
		}

		// Creating Combined file name
		$file_name = md5($combined_css);
		$file_name = substr($file_name, 0, 16) . '-combined.css';
		
		$asset_path = Util::cache_path('assets');
		if(!is_dir($asset_path)){
			mkdir($asset_path, 0755, true);
			touch($asset_path . 'index.html');
		}

		$combined_path = $asset_path.$file_name;

		file_put_contents($combined_path, $combined_css);
		$final_url = Util::path_to_url($combined_path);

		// Injecting the Combined CSS
		if(!empty($prev_tag)){
			$content = str_replace($prev_tag, '<link rel="stylesheet" href="'.esc_url($final_url).'" />', $content);
			return;
		}

		$content = str_replace('</title>', "</title>\n".'<link rel="stylesheet" href="'.esc_url($final_url).'" />', $content);
	}
	
	static function is_excluded($url){
		$excludes = get_option('speedycache_exclude', []);

		if(empty($excludes)){
			return false;
		}

		foreach($excludes as $exclude){
			if(empty($exclude['type'])){
				continue;
			}

			if($exclude['type'] !== 'css'){
				continue;
			}

			if(empty($exclude['content'])){
				continue;
			}

			if(preg_match('/'.preg_quote($exclude['content'], '/').'/', $url)){
				return true;
			}
		}

		return false;
	}
	
	static function fix_relative_path($content, $base_url){
		
		// We need base url as the relative url file will be in the same folder as file at the base url or will be relative to path of the base url
		$content = preg_replace_callback('/url\(\s*["\']?(?!http|https|\/\/)([^"\')]+)["\']?\s*\)/i', function($matches) use ($base_url) {
			$relative_path = $matches[1];
			$relative_path = trim($relative_path, '/');
			$base_path = Util::url_to_path($base_url);

			if(strpos($relative_path, '..') === 0 || strpos($relative_path, './') === 0){
				$parameter = '';
				// Some URL's had query parameters, that were breaking when using realpath
				if(strpos($relative_path, '?') !== FALSE){
					$parsed_path = explode('?', $relative_path);
					$parameter = $parsed_path[1];
					$relative_path = $parsed_path[0];
					$parsed_path = null;
				}

				$absolute_path = realpath(dirname($base_path) . '/' . $relative_path);
				$absolute_url = Util::path_to_url($absolute_path);
				
				// Appending the parameter again
				if(!empty($parameter)){
					$absolute_url .= '?'. $parameter;
				}
			} else if(strpos($relative_path, 'wp-content') === 0){
				$absolute_url = site_url() . '/'. $relative_path;
			}

			if(empty($absolute_url)){
				$absolute_url = $relative_path;
			}
			
			return 'url("' . $absolute_url . '")';
			
		}, $content);
		
		return $content;
	}
}
preload.php000064400000006571151526414160006721 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Preload{
	
	static function build_preload_list(){
		global $wp_rewrite;

		delete_transient('speedycache_preload_transient');

		if(!isset($wp_rewrite)){
			$wp_rewrite = new \WP_Rewrite();
		}

		$preload_urls = [];
		$preload_urls[] = home_url();

		$args = [
			'fields' => 'ids',
			'post_type' => ['post', 'page', 'product', 'docs'],
			'posts_per_page' => 80,
			'post_status' => 'publish',
			'orderby' => 'date',
			'order' => 'DESC',
			'has_password' => false,
		];
		
		$query = new \WP_Query($args);
		if($query->have_posts()){
			$posts = $query->get_posts();
			foreach($posts as $post_id){
				$preload_urls[] = get_permalink($post_id);
			}
		}

		$query = null;
		
		$args = [
			'fields' => 'ids',
			'post_type' => 'page',
			'posts_per_page' => 10,
			'post_status' => 'publish',
			'orderby' => 'date',
			'order' => 'DESC',
			'has_password' => false
		];

		$query = new \WP_Query($args);
		if($query->have_posts()){
			$posts = $query->get_posts();
			foreach($posts as $post_id){
				$preload_urls[] = get_permalink($post_id);
			}
		}

		$preload_urls = array_unique($preload_urls);

		set_transient('speedycache_preload_transient', $preload_urls, HOUR_IN_SECONDS);
		wp_schedule_single_event(time(), 'speedycache_preload_split');
	}

	static function cache(){
		global $speedycache;

		$preload_urls = get_transient('speedycache_preload_transient');
		$cache_urls = 0;

		if(empty($preload_urls) || !is_array($preload_urls)){
			return;
		}

		foreach($preload_urls as $key => $url){
			if($cache_urls >= 10){
				break;
			}

			wp_remote_get($url, [
				'headers' => [
					'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
				],
				'timeout' => 0.01,
				'blocking' => false,
				'sslverify' => false,
			]);

			// Preload mobile version too
			if(!empty($speedycache->options['mobile_theme'])){
				wp_remote_get($url, [
					'headers' => [
						'User-Agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/114.0.5735.99 Mobile/15E148 Safari/604.1'
					],
					'timeout' => 0.01,
					'blocking' => false,
					'sslverify' => false,
				]);
			}

			unset($preload_urls[$key]); // We remove from the list to be preloaded
			$cache_urls++;
		}
		
		if(empty($preload_urls)){
			set_transient('speedycache_preload_transient', [], HOUR_IN_SECONDS);
			return;
		}

		wp_schedule_single_event(time() + 60, 'speedycache_preload_split');
		set_transient('speedycache_preload_transient', $preload_urls, HOUR_IN_SECONDS);
	}
	
	// This will push a request to preload URLS
	// TODO: need to add a lock here
	static function url($urls){

		if(!is_array($urls)){
			$urls = [$urls];
		}

		$preload_urls = get_transient('speedycache_preload_transient');
		if(empty($preload_urls) || !is_array($preload_urls)){
			$preload_urls = [];
		}

		$preload_urls = array_merge($preload_urls, $urls);
		$preload_urls = array_unique($preload_urls);

		set_transient('speedycache_preload_transient', $preload_urls, HOUR_IN_SECONDS);

		if(!wp_next_scheduled('speedycache_preload_split')){
			wp_schedule_single_event(time() + 60, 'speedycache_preload_split');
		}
	}
}
imageseo.php000064400000006052151526415240007056 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class ImageSeo{

	static function init(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return; // toggle disable
		}
		
		if(!empty($siteseo->advanced_settings['advanced_attachments'])){
			add_action('template_redirect', '\SiteSEO\ImageSeo::redirect_attachment_to_parent');
		}

		if(!empty($siteseo->advanced_settings['advanced_clean_filename'])){
			add_filter('sanitize_file_name', '\SiteSEO\ImageSeo::clean_media_filename', 10, 1);
		}

		if(!empty($siteseo->advanced_settings['advanced_image_auto_alt_editor']) ||
			!empty($siteseo->advanced_settings['advanced_image_auto_caption_editor']) ||
			!empty($siteseo->advanced_settings['advanced_image_auto_desc_editor']) || 
			!empty($siteseo->advanced_settings['advanced_image_auto_title_editor'])
		){
			add_action('add_attachment', '\SiteSEO\ImageSeo::set_image_content');
		}
	}
	
	static function set_image_content($attachment_id){
		global $siteseo;

		if(!wp_attachment_is_image($attachment_id)){
			return;
		}
		
		$attachment = get_post($attachment_id);
		$file_name = pathinfo($attachment->guid, PATHINFO_FILENAME);
		$file_name = sanitize_file_name($file_name);
		$file_name = ucwords(str_replace(['-', '_'], ' ', $file_name));
		
		// WooCommerce product img
		$is_woocommerce_product_image = false;
		$product_title = '';
		
		$parent_id = $attachment->post_parent;
		if(!empty($parent_id)){
			$parent_post = get_post($parent_id);
			if(!empty($parent_post) && $parent_post->post_type === 'product'){
				$is_woocommerce_product_image = true;
				$product_title = get_the_title($parent_id);
			}
		}
		
		$file_name = $is_woocommerce_product_image ? $product_title : $file_name;
		
		// Adding alt text to the image
		if(!empty($siteseo->advanced_settings['advanced_image_auto_alt_editor'])){
			update_post_meta($attachment_id, '_wp_attachment_image_alt', $file_name);
		}

		$options = [];
		$options['ID'] = $attachment_id;

		// Adding Title to the image
		if(!empty($siteseo->advanced_settings['advanced_image_auto_title_editor'])){
			$options['post_title'] = $file_name;
		}

		// Adding Img Caption
		if(!empty($siteseo->advanced_settings['advanced_image_auto_caption_editor'])){
			$options['post_content'] = $file_name;
		}

		// Adding Img Caption
		if(!empty($siteseo->advanced_settings['advanced_image_auto_desc_editor'])){
			$options['post_excerpt'] = $file_name;
		}

		if(count($options) > 1){
			wp_update_post($options);
		}
	}
	
	static function clean_media_filename($filename){
		$filename = strtolower($filename);		
		$filename = preg_replace('/[^a-z0-9-._]+/', '-', $filename);
		$filename = trim($filename, '-.');

		return $filename;
	}

	static function redirect_attachment_to_parent(){

		if(is_attachment()){
 
			$attachment_id = get_queried_object_id();
			$parent_id = wp_get_post_parent_id($attachment_id);

			if($parent_id){
				wp_redirect(get_permalink($parent_id));

			}else{
				wp_redirect(home_url());
			}

			exit; 
		}
	}
}
settings/statistics.php000064400000143411151526415240011320 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Statistics{

	static function init(){
		global $siteseo;

		$current_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'tab_dashbord';

		wp_enqueue_script('siteseo-chart-js', SITESEO_ASSETS_URL . '/js/chart.umd.min.js', [], SITESEO_VERSION, ['strategy' => 'defer', 'in_footer' => true]);
		wp_enqueue_script('siteseo-gsc-charts', SITESEO_ASSETS_URL . '/js/gsc-charts.js', ['jquery', 'siteseo-chart-js'], SITESEO_VERSION, ['strategy' => 'defer', 'in_footer' => true]);

		$saved_data = get_option('siteseo_search_console_data', []);
		wp_localize_script('siteseo-gsc-charts', 'siteseo_chart_data', $saved_data);

		if(isset($_GET['siteseo_auth_code']) && class_exists('\SiteSEOPro\GoogleConsole') && method_exists('\SiteSEOPro\GoogleConsole', 'generate_tokens')){
			\SiteSEOPro\GoogleConsole::generate_tokens();
		}

		if(isset($_GET['siteseo_auth_code']) && class_exists('\SiteSEOPro\GoogleConsole')){
			add_action('admin_footer', '\SiteSEO\Settings\Statistics::connect_site_dialogbox');
		}

		$site_connected = false;
		if(class_exists('\SiteSEOPro\GoogleConsole') && method_exists('\SiteSEOPro\GoogleConsole', 'is_connected')){
			$site_connected = \SiteSEOPro\GoogleConsole::is_connected();
		}

		$statistics_subtabs = [
			'tab_dashbord' => esc_html__('Dashboard', 'siteseo'),
			'tab_seo_statistics' => esc_html__('Site Search Traffic', 'siteseo'),
			'tab_keyword_rank' => esc_html__('Keyword Rank Tracker', 'siteseo'),
			'tab_content_ranking' => esc_html__('Content Ranking', 'siteseo'),
			'tab_audience' => esc_html__('Audience Overview', 'siteseo'),
		];

		echo'<div id="siteseo-root" class="siteseo-search-console">';
		Util::admin_header();

		$show_sample_data = isset($_GET['sample_data']) && $_GET['sample_data'] === '1';

		if(!class_exists('\SiteSEOPro\GoogleConsole') && !$show_sample_data){
			echo'<div class="siteseo-blur-overlay"></div>
			<div class="siteseo-pro-notice-center">
				<div class="siteseo-pro-notice-content">
					<span class="dashicons dashicons-lock siteseo-lock-icon"></span>
					<h2>'.esc_html__('Search Console Pro Feature', 'siteseo').'</h2>
					<p>'.esc_html__('Upgrade to PRO to unlock Google Search Console integration and access real-time search analytics data.', 'siteseo').'</p>
					<div class="siteseo-option siteseo-pro-notice-buttons">
					<a href="https://siteseo.io/pricing" class="siteseo-option btnPrimary" target="_blank">' . esc_html__('Buy Pro', 'siteseo') . '</a>
					<a href="'.esc_url(add_query_arg('sample_data', '1')).'" class="siteseo-option btnSecondary">'.esc_html__('Explore Sample Data', 'siteseo').'</a>
				</div>
			</div>
			</div>';
		} elseif(class_exists('\SiteSEOPro\GoogleConsole') && !$show_sample_data && empty($site_connected)){
			echo'<div class="siteseo-blur-overlay"></div>
			<div class="siteseo-pro-notice-center">
				<div class="siteseo-pro-notice-content">
					<span class="dashicons dashicons-admin-links siteseo-link-icon"></span>
					<h2>'.esc_html__('Search Console statistics', 'siteseo').'</h2>
					<p>'.esc_html__('Please connect your Google Search Console account to unlock real-time search analytics data.', 'siteseo').'</p>
					<div class="siteseo-option siteseo-pro-notice-buttons">
					<form method="post">';
					wp_nonce_field('siteseo_pro_connect_google');
					echo '<input type="hidden" name="redirect_type" value="settings">
						<button type="submit" name="siteseo_pro_connect_btn" class="siteseo-option btnPrimary siteseo-connect-btn">'.esc_html__('Connect Search Console', 'siteseo') .'</button>
					</form>
					<a href="'.esc_url(add_query_arg('sample_data', '1')).'" class="siteseo-option btnSecondary">'.esc_html__('Explore Sample Data', 'siteseo').'</a>
				</div>
			</div>
			</div>';
		}

		echo'<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">
		<div class="siteseo-toggle-cnt"><span id="siteseo-tab-title"><strong>'.esc_html__('Google Search Console Statistics', 'siteseo').'</strong></span></div>';

		if(!empty($site_connected)){

			if(class_exists('\SiteSEOPro\GoogleConsole') && method_exists('\SiteSEOPro\GoogleConsole', 'get_site_url')){
				$site_url = \SiteSEOPro\GoogleConsole::get_site_url();
			}

			if(!empty($site_url)){
				echo'<div class="siteseo-statistics-wrapper">
					<span class="siteseo-statistics-sites">Site: '.(strpos($site_url, 'sc-domain:') === 0 ? sanitize_text_field($site_url) : esc_url($site_url)).' <span id="siteseo-refresh-search-stats" class="dashicons dashicons-update" title="'.esc_attr__('Update Stats', 'siteseo').'"></span></span>
					<span class="siteseo-statistics-disconnect"><span class="dashicons dashicons-migrate"></span>'.esc_html__('Disconnect', 'siteseo').'</span>
					<span class="siteseo-statistics-data-range">'.esc_html__('[Last 90 days data]', 'siteseo').'</span>
				</div>';
			}
		}

		echo'<div id="siteseo-tabs" class="wrap">
		<div class="siteseo-nav-tab-wrapper">';

		foreach($statistics_subtabs as $tab_key => $tab_caption){
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo'<a id="' . esc_attr($tab_key) . '-tab" class="siteseo-nav-tab' . esc_attr($active_class) . '" data-tab="' . esc_attr($tab_key) . '">' . esc_html($tab_caption) . '</a>';
		}

		echo'</div>
		<div class="tab-content-wrapper">
		<div class="siteseo-tab' .($current_tab == 'tab_dashbord' ? ' active' : '').'" id="tab_dashbord" style="display: none;">';
		self::dashbord_tab();
		echo'</div>
		<div class="siteseo-tab' .($current_tab == 'tab_seo_statistics' ? ' active' : '').'" id="tab_seo_statistics" style="display: none;">';
		self::seo_statistics_tab();
		echo'</div>
		<div class="siteseo-tab' .($current_tab == 'tab_keyword_rank' ? ' active' : '').'" id="tab_keyword_rank" style="display: none;">';
		self::keyword_ranking_tab();
		echo'</div>
		<div class="siteseo-tab' .($current_tab == 'tab_content_ranking' ? ' active' : '').'" id="tab_content_ranking" style="display: none;">';
		self::content_ranking_tab();
		echo'</div>
		<div class="siteseo-tab '.($current_tab =='tab_audience' ? ' active' : '').'" id="tab_audience" style="display:none;">';
		self::audience_tab();
		echo'</div>
		</div>';
		echo'</form></div>';
	}

	static function fetch_data(){
		$is_connected = '';

		if(class_exists('\SiteSEOPro\GoogleConsole') && method_exists('\SiteSEOPro\GoogleConsole', 'is_connected')){
			$is_connected = \SiteSEOPro\GoogleConsole::is_connected();
		}

		$analytics_data = get_option('siteseo_search_console_data', []);

		if(empty($analytics_data) && empty($is_connected)){
			// Show sample data when not connected
			return [
				'metrics' => self::sample_metrics_data(),
				'top_pages' => self::sample_top_pages(),
				'top_loss_pages' => array_slice(self::sample_top_pages(), 0, 3), // Sample loss pages
				'top_winning_pages' => array_slice(self::sample_top_pages(), 3, 3), // Sample winning pages
				'keywords' => self::sample_keywords(),
				'top_winning_keywords' => array_slice(self::sample_keywords(), 0, 3), // Sample winning keywords
				'top_loss_keywords' => array_slice(self::sample_keywords(), 3, 2), // Sample loss keywords
				'content_ranking' => self::sample_content_ranking(),
				'country_data' => self::sample_country_data(), 
				'device_data' => self::sample_device_data(),
				'is_sample' => true
			];
		}
		
		return [
			'metrics' => isset($analytics_data['metrics']) ? $analytics_data['metrics'] : [
				'impressions' => [
					'current' => '0',
					'change' => '0',
					'trend' => 'neutral',
					'chart_data' => []
				],
				'clicks' => [
					'current' => '0',
					'change' => '0',
					'trend' => 'neutral',
					'chart_data' => []
				],
				'ctr' => [
					'current' => '0%',
					'change' => '0',
					'trend' => 'neutral',
					'chart_data' => []
				],
				'position' => [
					'current' => '0',
					'change' => '0',
					'trend' => 'neutral',
					'chart_data' => []
				]
			],
			'top_pages' => isset($analytics_data['top_pages']) ? array_slice($analytics_data['top_pages'], 0, 5) : [],
			'top_loss_pages' => isset($analytics_data['top_loss_pages']) ? array_slice($analytics_data['top_loss_pages'], 0, 5) : [],
			'top_winning_pages' => isset($analytics_data['top_winning_pages']) ? array_slice($analytics_data['top_winning_pages'], 0, 5) : [],
			'keywords' => isset($analytics_data['top_keywords']) ? array_slice($analytics_data['top_keywords'], 0, 5) : [],
			'top_winning_keywords' => isset($analytics_data['top_winning_keywords']) ? array_slice($analytics_data['top_winning_keywords'], 0, 5) : [],
			'top_loss_keywords' => isset($analytics_data['top_loss_keywords']) ? array_slice($analytics_data['top_loss_keywords'], 0, 5) : [],
			'content_ranking' => isset($analytics_data['content_ranking']) ? $analytics_data['content_ranking'] : [],
			'country_data' => isset($analytics_data['country_audience']) ? $analytics_data['country_audience'] : [],
			'device_data' => isset($analytics_data['device_audience']) ? $analytics_data['device_audience'] : [],
			'is_sample' => false
		];
	}

	static function dashbord_tab(){	
		self::connect_notices();

		$data = self::fetch_data();
		$metrics = $data['metrics'];
		$top_pages = $data['top_pages'];
		$top_loss_pages = $data['top_loss_pages'];
		$top_winning_pages = $data['top_winning_pages'];
		$keywords = $data['keywords'];
		$top_winning_keywords = $data['top_winning_keywords'];
		$top_loss_keywords = $data['top_loss_keywords'];

		echo'<div class="siteseo-stats-container">
			<h2 class="siteseo-stats-title">'.esc_html__('Search Performance', 'siteseo').'</h2>
			<hr class="siteseo-stats-separator">

			<div class="siteseo-dashboard-grid">
				<div class="siteseo-metric-card">
					<div class="siteseo-metric-header">
						<span class="siteseo-metric-title">'.esc_html__('Search Impressions', 'siteseo').'</span>
					</div>
					
					<div class="siteseo-metric-value-row">
						<span class="siteseo-metric-value">'.esc_html($metrics['impressions']['current']).'</span>
							<span class="siteseo-metric-change '.($metrics['impressions']['trend'] == 'negative' ? 'siteseo-change-negative' : ($metrics['impressions']['trend'] == 'positive' ? 'siteseo-change-positive' : '')).'">
								'.($metrics['impressions']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['impressions']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
								'.esc_html($metrics['impressions']['change']).'
							</span>
					</div>
						
					<div class="siteseo-chart-container">
						<canvas id="siteseo_impressions_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
					</div>
				</div>

					<div class="siteseo-metric-card">
						<div class="siteseo-metric-header">
							<span class="siteseo-metric-title">'.esc_html__('Total Clicks', 'siteseo').'</span>
						</div>
						
						<div class="siteseo-metric-value-row">
							<span class="siteseo-metric-value">'.esc_html($metrics['clicks']['current']).'</span>
							<span class="siteseo-metric-change '.($metrics['clicks']['trend'] == 'negative' ? 'siteseo-change-negative' : ($metrics['clicks']['trend'] == 'positive' ? 'siteseo-change-positive' : '')).'">
								'.($metrics['clicks']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['clicks']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
								'.esc_html($metrics['clicks']['change']).'
							</span>
						</div>
						
						<div class="siteseo-chart-container">
							<canvas id="siteseo_clicks_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
						</div>
					</div>

					<div class="siteseo-metric-card">
						<div class="siteseo-metric-header">
							<span class="siteseo-metric-title">'.esc_html__('Avg. CTR', 'siteseo').'</span>
						</div>
						<div class="siteseo-metric-value-row">
							<span class="siteseo-metric-value">'.esc_html($metrics['ctr']['current']).'</span>
							<span class="siteseo-metric-change '.($metrics['ctr']['trend'] == 'negative' ? 'siteseo-change-negative' : ($metrics['ctr']['trend'] == 'positive' ? 'siteseo-change-positive' : '')).'">
								'.($metrics['ctr']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['ctr']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
								'.esc_html($metrics['ctr']['change']).'
							</span>
						</div>
						<div class="siteseo-chart-container">
							<canvas id="siteseo_ctr_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
						</div>
					</div>

					<div class="siteseo-metric-card">
						<div class="siteseo-metric-header">
							<span class="siteseo-metric-title">'.esc_html__('Avg. Position', 'siteseo').'</span>
						</div>
						<div class="siteseo-metric-value-row">
							<span class="siteseo-metric-value">'.esc_html($metrics['position']['current']).'</span>
							<span class="siteseo-metric-change '.($metrics['position']['trend'] == 'negative' ? 'siteseo-change-negative' : ($metrics['position']['trend'] == 'positive' ? 'siteseo-change-positive' : '')).'">
								'.($metrics['position']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['position']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
								'.esc_html($metrics['position']['change']).'
							</span>
						</div>
						<div class="siteseo-chart-container">
							<canvas id="siteseo_position_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
						</div>
					</div>
				</div>
			</div>';
		
		if(!empty($top_pages) || $data['is_sample']){

			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Content Performance ( Top 5 )', 'siteseo').'</h2>
				<div class="siteseo-inner-tabs-wrap">
					<input type="radio" id="siteseo-statistics-top-page" name="siteseo-inner-tabs-pages" checked>
					<input type="radio" id="siteseo-statistics-top-loss" name="siteseo-inner-tabs-pages">
					<input type="radio" id="siteseo-statistics-top-winning" name="siteseo-inner-tabs-pages">
					
					<ul class="siteseo-inner-tabs">
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-top-page">'.esc_html__('Top Pages', 'siteseo').'</label></li>
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-top-loss">'.esc_html__('Top loss', 'siteseo').'</label></li>
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-top-winning">'.esc_html__('Top winning', 'siteseo').'</label></li>
					</ul>
						
					<div class="siteseo-inner-tab-content">	
						<table class="wp-list-table widefat fixed striped siteseo-history-table">
							<thead><tr>
								<th>'.esc_html__('Title', 'siteseo').'</th>
								<th>'.esc_html__('Score', 'siteseo').'</th>
								<th>'.esc_html__('Indexed', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Impressions', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>
								<th>'.esc_html__('Diff', 'siteseo').'</th>
							</tr>
							</thead>
						<tbody>';

						foreach($top_pages as $page){
							
							$score = $page['truseo_score'];
							
							if($score >= 80){
								$badge_class = 'siteseo-gsc-score-good';
							} elseif ($score >= 50){
								$badge_class = 'siteseo-gsc-score-avg';
							} else{
								$badge_class = 'siteseo-gsc-score-bad';
							}
							
							echo'<tr>
								<td>'.esc_html($page['title']).'</td>
								<td><span class="'.esc_attr($badge_class).'">'.esc_html($page['truseo_score']).'/100</span></td>
								<td><span class="dashicons '.($page['indexed'] ? 'dashicons-yes-alt siteseo-statistics-index-icon' : 'dashicons-dismiss siteseo-statistics-noindex-icon').'"></span></td>
								<td>'.esc_html($page['clicks']).'</td>
								<td>'.esc_html($page['impressions']).'</td>
								<td>'.esc_html($page['position']).'</td>
								<td style="color:'.(isset($page['diff']) && strpos($page['diff'], '+') === 0 ? '#28a745' : '#dc3545').';">'.esc_html($page['diff']).'</td>
							</tr>';
						}
						
						if(empty($top_pages) && !$data['is_sample']){
							echo '<tr><td colspan="7" style="text-align:center;">'.esc_html__('No data available yet', 'siteseo').'</td></tr>';
						}
						
						echo'</tbody></table>
					</div>
					
					<div class="siteseo-inner-tab-content">
						 <table class="wp-list-table widefat fixed striped siteseo-history-table">
							<thead><tr>
								<th>'.esc_html__('Title', 'siteseo').'</th>
								<th>'.esc_html__('Score', 'siteseo').'</th>
								<th>'.esc_html__('Indexed', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Impressions', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>
								<th>'.esc_html__('Diff', 'siteseo').'</th>
							</tr>
							</thead>
						<tbody>';

						// Use top_loss_pages instead of top_pages
						foreach($top_loss_pages as $page){
							
							$score = $page['truseo_score'];
							
							if($score >= 80){
								$badge_class = 'siteseo-gsc-score-good';
							} elseif($score >= 50){
								$badge_class = 'siteseo-gsc-score-avg';
							} else{
								$badge_class = 'siteseo-gsc-score-bad';
							}
							
							echo'<tr>
								<td>'.esc_html($page['title']).'</td>
								<td><span class="'.esc_attr($badge_class).'">'.esc_html($page['truseo_score']).'/100</span></td>
								<td><span class="dashicons '.($page['indexed'] ? 'dashicons-yes-alt siteseo-statistics-index-icon' : 'dashicons-dismiss siteseo-statistics-noindex-icon').'"></span></td>
								<td>'.esc_html($page['clicks']).'</td>
								<td>'.esc_html($page['impressions']).'</td>
								<td>'.esc_html($page['position']).'</td>
								<td style="color:#dc3545;">'.esc_html($page['diff']).'</td>
							</tr>';
						}
						
						if(empty($top_loss_pages) && !$data['is_sample']){
							echo '<tr><td colspan="7" style="text-align:center;">'.esc_html__('No loss pages data available', 'siteseo').'</td></tr>';
						}

						echo'</tbody></table>
					</div>
					
					<div class="siteseo-inner-tab-content">
						 <table class="wp-list-table widefat fixed striped siteseo-history-table">
							<thead><tr>
								<th>'.esc_html__('Title', 'siteseo').'</th>
								<th>'.esc_html__('Score', 'siteseo').'</th>
								<th>'.esc_html__('Indexed', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Impressions', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>
								<th>'.esc_html__('Diff', 'siteseo').'</th>
							</tr>
							</thead>
						<tbody>';

						// Use top_winning_pages instead of top_pages
						foreach($top_winning_pages as $page){
							$score = $page['truseo_score'];
							if($score >= 80){
								$badge_class = 'siteseo-gsc-score-good';
							} elseif($score >= 50){
								$badge_class = 'siteseo-gsc-score-avg';
							} else{
								$badge_class = 'siteseo-gsc-score-bad';
							}
							
							echo'<tr>
								<td>'.esc_html($page['title']).'</td>
								<td><span class="'.esc_attr($badge_class).'">'.esc_html($page['truseo_score']).'/100</span></td>
								<td><span class="dashicons '.($page['indexed'] ? 'dashicons-yes-alt siteseo-statistics-index-icon' : 'dashicons-dismiss siteseo-statistics-noindex-icon').'"></span></td>
								<td>'.esc_html($page['clicks']).'</td>
								<td>'.esc_html($page['impressions']).'</td>
								<td>'.esc_html($page['position']).'</td>
								<td style="color:#28a745;">'.esc_html($page['diff']).'</td>
							</tr>';
						}
						
						if(empty($top_winning_pages) && !$data['is_sample']){
							echo '<tr><td colspan="7" style="text-align:center;">'.esc_html__('No winning pages data available', 'siteseo').'</td></tr>';
						}
						
						echo'</tbody></table>
					</div>
				</div>
			</div>';
		}
		
		if(!empty($keywords) || $data['is_sample']){
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Keyword Rankings ( Top 5 )', 'siteseo').'</h2>

				<div class="siteseo-inner-tabs-wrap">
					<input type="radio" id="siteseo-statistics-top-keywords" name="siteseo-inner-tabs-keywords" checked>
					<input type="radio" id="siteseo-statistics-winning-keywords" name="siteseo-inner-tabs-keywords">
					<input type="radio" id="siteseo-statistics-loss-keywords" name="siteseo-inner-tabs-keywords">

					<ul class="siteseo-inner-tabs">
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-top-keywords">'.esc_html__('Top Keywords', 'siteseo').'</label></li>
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-winning-keywords">'.esc_html__('Top Winning', 'siteseo').'</label></li>
						<li class="siteseo-inner-tab"><label for="siteseo-statistics-loss-keywords">'.esc_html__('Top LOSS', 'siteseo').'</label></li>
					</ul>
						
				<div class="siteseo-inner-tab-content">	

					<table class="wp-list-table widefat fixed striped siteseo-history-table">
						<thead>
							<tr>
								<th>'.esc_html__('Keyword', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Impressions', 'siteseo').'</th>
								<th>'.esc_html__('CTR', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>
							</tr>
						</thead>
						<tbody>';
						
						foreach($keywords as $keyword){
							echo'<tr>
								<td class="siteseo-table-row">'.esc_html($keyword['keyword']).'</td>
								<td style="font-weight:bold;">'.esc_html($keyword['clicks']).'</td>
								<td>'.esc_html($keyword['impressions']).'</td>
								<td>'.esc_html($keyword['ctr']).'</td>
								<td>'.esc_html($keyword['position']).'</td>
							</tr>';
						}
						
						if(empty($keywords) && !$data['is_sample']){
							echo'<tr><td colspan="5" style="text-align:center;">'.esc_html__('No data available yet', 'siteseo').'</td></tr>';
						}
						
						echo'</tbody>
					</table>
				</div>
				<div class="siteseo-inner-tab-content">
					<table class="wp-list-table widefat fixed striped siteseo-history-table">
						<thead>
							<tr>
								<th>'.esc_html__('Keyword', 'siteseo').'</th>
								<th>'.esc_html__('Points', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>
							</tr>
						</thead>
						<tbody>';
						
						// Use top_winning_keywords instead of keywords
						foreach($top_winning_keywords as $keyword){
							echo'<tr>
								<td class="siteseo-table-row">'.esc_html($keyword['keyword']).'</td>
								<td style="color:#28a745;font-weight:bold;">'.esc_html($keyword['points']).'</td>
								<td>'.esc_html($keyword['clicks']).'</td>
								<td>'.esc_html($keyword['position']).'</td>
							</tr>';
						}
						
						if(empty($top_winning_keywords) && !$data['is_sample']){
							echo'<tr><td colspan="4" style="text-align:center;">'.esc_html__('No winning keywords data available', 'siteseo').'</td></tr>';
						}

						echo'</tbody>
					</table>
				</div>

				<div class="siteseo-inner-tab-content">
					<table class="wp-list-table widefat fixed striped siteseo-history-table">
						<thead>
							<tr>
								<th>'.esc_html__('Keyword', 'siteseo').'</th>
								<th>'.esc_html__('Points', 'siteseo').'</th>
								<th>'.esc_html__('Clicks', 'siteseo').'</th>
								<th>'.esc_html__('Position', 'siteseo').'</th>	   
							</tr>
						</thead>
						<tbody>';

						// Use top_loss_keywords instead of keywords
						foreach($top_loss_keywords as $keyword){
							echo'<tr>
								<td class="siteseo-table-row">'.esc_html($keyword['keyword']).'</td>
								<td style="color:#dc3545;font-weight:bold;">'.esc_html($keyword['points']).'</td>
								<td>'.esc_html($keyword['clicks']).'</td>
								<td>'.esc_html($keyword['position']).'</td>
							</tr>';
						}

						if(empty($top_loss_keywords) && !$data['is_sample']){
							echo'<tr><td colspan="4" style="text-align:center;">'.esc_html__('No loss keywords data available', 'siteseo').'</td></tr>';
						}

						echo'</tbody>
					</table>
				</div>
				</div>
			</div>';
		}
	}

	static function seo_statistics_tab(){
		self::connect_notices();

		$data = self::fetch_data();
		$metrics = $data['metrics'];
		$top_pages = $data['top_pages'];
		
		echo'<div class="siteseo-stats-container">
			<h2 class="siteseo-stats-title">'.esc_html__('Site Search Traffic', 'siteseo').'</h2>
			<hr class="siteseo-stats-separator">
			<ul class="siteseo-stats-list">
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Search Impressions', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($metrics['impressions']['current']).'</span>
						<span class="siteseo-stat-change '.($metrics['impressions']['trend'] == 'negative' ? 'negative' : ($metrics['impressions']['trend'] == 'positive' ? 'positive' : '')).'">
							'.($metrics['impressions']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['impressions']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
							'.esc_html($metrics['impressions']['change']).'
						</span>
					</div>
				</li>
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Total Clicks', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($metrics['clicks']['current']).'</span>
						<span class="siteseo-stat-change '.($metrics['clicks']['trend'] == 'negative' ? 'negative' : ($metrics['clicks']['trend'] == 'positive' ? 'positive' : '')).'">
							'.($metrics['clicks']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['clicks']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
							'.esc_html($metrics['clicks']['change']).'
						</span>
					</div>
				</li>
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Avg. CTR', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($metrics['ctr']['current']).'</span>
						<span class="siteseo-stat-change '.($metrics['ctr']['trend'] == 'negative' ? 'negative' : ($metrics['ctr']['trend'] == 'positive' ? 'positive' : '')).'">
							'.($metrics['ctr']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-'.($metrics['ctr']['trend'] == 'negative' ? 'down' : 'up').'"></span>' : '').'
							'.esc_html($metrics['ctr']['change']).'
						</span>
					</div>
				</li>
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Avg. Position.', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($metrics['position']['current']).'</span>
						<span class="siteseo-stat-change '.($metrics['position']['trend'] == 'negative' ? 'negative' : ($metrics['position']['trend'] == 'positive' ? 'positive' : '')) . '">
						'.($metrics['position']['trend'] != 'neutral' ? '<span class="dashicons dashicons-arrow-' . ($metrics['position']['trend'] == 'negative' ? 'down' : 'up') . '"></span>' : ''
							) . '
							'.esc_html($metrics['position']['change']).'
						</span>
					</div>
				</li>
			</ul>
		   <canvas id="seo_statistics" width="950" height="250" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
		</div>';
		
		if(!empty($top_pages) || $data['is_sample']){
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Content Analysis ( Top 5 )', 'siteseo').'</h2>	
				<table class="wp-list-table widefat fixed striped siteseo-history-table">
					<thead><tr>
						<th>'.esc_html__('Page', 'siteseo').'</th>
						<th>'.esc_html__('Status', 'siteseo').'</th>
						<th>'.esc_html__('Clicks', 'siteseo').'</th>
						<th>'.esc_html__('Avg position', 'siteseo').'</th>
						<th>'.esc_html__('Impressions', 'siteseo').'</th>
						<th>'.esc_html__('Content Score', 'siteseo').'</th>
					</tr>
					</thead>
				<tbody>';
				
				foreach($top_pages as $page){
					
					$score = $page['truseo_score'];
					if($score >= 80){
						$badge_class = 'siteseo-gsc-score-good';
					} elseif ($score >= 50){
						$badge_class = 'siteseo-gsc-score-avg';
					} else{
						$badge_class = 'siteseo-gsc-score-bad';
					}
						
					echo'<tr>
						<td>'.esc_html($page['title']).'</td>
						<td>'.(isset($page['indexed']) ? ($page['indexed'] ? '<span class="dashicons dashicons-yes-alt" style="color:#28a745;"></span>' : '<span class="dashicons dashicons-dismiss" style="color:#dc3545;"></span>') : '<span class="dashicons dashicons-editor-help" style="color:#6c757d;"></span>').'</td>
						<td>'.esc_html($page['clicks']).'</td>
						<td>'.esc_html($page['position']).'</td>
						<td>'.esc_html($page['impressions']).'</td>
						<td><span class="'.esc_attr($badge_class).'">'.esc_html($page['truseo_score']).'/100</span></td>
					</tr>';
				}
				
				if(empty($top_pages) && !$data['is_sample']){
					echo'<tr><td colspan="6" style="text-align:center;">'.esc_html__('No data available yet', 'siteseo').'</td></tr>';
				}
				
				echo'</tbody></table>
			</div>';
		}
	}
		
	static function keyword_ranking_tab(){
		self::connect_notices();
	
		$data = self::fetch_data();
		$keywords = $data['keywords'];

		// Get actual analytics data if available
		$analytics_data = get_option('siteseo_search_console_data', []);
		$has_actual_data = !empty($analytics_data) && !isset($analytics_data['error']);
	
		// Prepare values based on actual data or sample
		if($has_actual_data && !$data['is_sample']){
			// Use actual data
			$total_keywords = isset($analytics_data['top_keywords']) ? count($analytics_data['top_keywords']) : 0;
			$total_impressions = isset($analytics_data['metrics']['impressions']['current']) ? $analytics_data['metrics']['impressions']['current'] : '0';
			$avg_ctr = isset($analytics_data['metrics']['ctr']['current']) ? $analytics_data['metrics']['ctr']['current'] : '0%';
			
			$impression_change = isset($analytics_data['metrics']['impressions']['change']) ? $analytics_data['metrics']['impressions']['change'] : '0';
			$impression_trend = isset($analytics_data['metrics']['impressions']['trend']) ? $analytics_data['metrics']['impressions']['trend'] : 'neutral';
			
			$ctr_change = '0';
			$ctr_trend = 'neutral';
			
		} else{
			// Use sample data or zeros
			$total_keywords = $data['is_sample'] ? '19K' : '0';
			$total_impressions = $data['is_sample'] ? '15M' : '0';
			$avg_ctr = $data['is_sample'] ? '48.25%' : '0%';
			$impression_change = $data['is_sample'] ? '475.7K' : '0';
			$impression_trend = $data['is_sample'] ? 'negative' : 'neutral';
			$ctr_change = $data['is_sample'] ? '1' : '0';
			$ctr_trend = $data['is_sample'] ? 'negative' : 'neutral';
		}
	
		echo'<div class="siteseo-stats-container">
			<h2 class="siteseo-stats-title">'.esc_html__('Keyword Positions', 'siteseo').'</h2>
			<hr class="siteseo-stats-separator">
			<ul class="siteseo-stats-list">
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Total Keyword', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($total_keywords).'</span>
						'.($data['is_sample'] ? '<span class="siteseo-stat-change positive">
							<span class="dashicons dashicons-arrow-up"></span>2.9K
						</span>' : '').'
					</div>
				</li>
			
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Search Impressions', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($total_impressions).'</span>
						'.((!$data['is_sample'] && $has_actual_data) ? 
						'<span class="siteseo-stat-change '.esc_attr($impression_trend).'">
							<span class="dashicons dashicons-arrow-'.($impression_trend === 'positive' ? 'up' : 'down').'"></span>'
							.esc_html($impression_change).'
						</span>' : 
						($data['is_sample'] ? 
						'<span class="siteseo-stat-change negative">
							<span class="dashicons dashicons-arrow-down"></span>475.7K
						</span>' : '')).'
					</div>
				</li>
			
				<li class="siteseo-stat-item">
					<div class="siteseo-stat-header">
						<span class="siteseo-stat-label">'.esc_html__('Avg. CTR', 'siteseo').'</span>
					</div>
					<div class="siteseo-stat-value-group">
						<span class="siteseo-stat-value">'.esc_html($avg_ctr).'</span>
						'.($data['is_sample'] ? 
						'<span class="siteseo-stat-change negative">
							<span class="dashicons dashicons-arrow-down"></span>1
						</span>' : '').'
					</div>
				</li>
			</ul>
		
			<div style="display:flex; gap:20px; flex-wrap:wrap;">
				<div style="flex:1; min-width:280px; max-width:50%;">
					<canvas id="siteseo_keyword_muti_line_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'" data-actual="'.($has_actual_data ? '1' : '0').'"></canvas>
				</div>
				<div style="flex:1; min-width:280px; max-width:50%;">
					<canvas id="siteseo_keyword_bar_chart" data-sample="'.($data['is_sample'] ? '1' : '0').'" data-actual="'.($has_actual_data ? '1' : '0').'"></canvas>
				</div>
			</div>
		</div>';
		
		if(!empty($keywords) || $data['is_sample']){
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Content Analysis ( Top 5 )', 'siteseo').'</h2>
				<table class="wp-list-table widefat fixed striped siteseo-history-table">
					<thead><tr>
						<th>'.esc_html__('Keywords', 'siteseo').'</th>
						<th>'.esc_html__('Clicks', 'siteseo').'</th>
						<th>'.esc_html__('Avg. CTR', 'siteseo').'</th>
						<th>'.esc_html__('Impressions', 'siteseo').'</th>
						<th>'.esc_html__('Position', 'siteseo').'</th>
					</tr>
					</thead>
				<tbody>';
				
				foreach($keywords as $keyword){
					echo'<tr>
						<td class="siteseo-table-row">'.esc_html($keyword['keyword']).'</td>
						<td>'.esc_html($keyword['clicks']).'</td>
						<td>'.esc_html($keyword['ctr']).'</td>
						<td>'.esc_html($keyword['impressions']).'</td>
						<td>'.esc_html($keyword['position']).'</td>
					</tr>';
				}
				
				if(empty($keywords) && !$data['is_sample']){
					echo'<tr><td colspan="6" style="text-align:center;">'.esc_html__('No data available yet', 'siteseo').'</td></tr>';
				}
				
				echo'</tbody></table>
			</div>';
		}
	}

	static function content_ranking_tab(){
		self::connect_notices();
		
		$data = self::fetch_data();
		$content_ranking = $data['content_ranking'];

		if(!empty($content_ranking) || $data['is_sample']){
			// Pagination setup
			$items_per_page = 10;
			$total_items = count($content_ranking);
			$total_pages = ceil($total_items / $items_per_page);
			
			$current_page = isset($_GET['cr_page']) ? max(1, intval($_GET['cr_page'])) : 1;

			$offset = ($current_page - 1) * $items_per_page;
			
			$paged_items = array_slice($content_ranking, $offset, $items_per_page);
			
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Content Analysis (Top 30)', 'siteseo').'</h2>
				<table class="wp-list-table widefat fixed striped siteseo-history-table">
					<thead><tr>
						<th>'.esc_html__('Title', 'siteseo').'</th>
						<th>'.esc_html__('Indexed', 'siteseo').'</th>
						<th>'.esc_html__('Last Update on', 'siteseo').'</th>
						<th>'.esc_html__('Loss', 'siteseo').'</th>
						<th>'.esc_html__('Drop (%)', 'siteseo').'</th>
						<th>'.esc_html__('Performance Score', 'siteseo').'</th>
					</tr>
					</thead>
				<tbody>';

				foreach($paged_items as $content){
					$score = (int) explode('/', $content['performance_score'])[0];
					
					if($score >= 80){
						$badge_class = 'siteseo-gsc-score-good';
					} elseif($score >= 50){
						$badge_class = 'siteseo-gsc-score-avg';
					} else{
						$badge_class = 'siteseo-gsc-score-bad';
					}
					
					echo'<tr>
						<td>'.esc_html($content['title']).'</td> 
						<td><span class="dashicons '.($content['indexed'] === 'Yes' ? 'dashicons-yes-alt siteseo-statistics-index-icon' : 'dashicons-dismiss siteseo-statistics-noindex-icon').'"></span></td>
						<td>'.esc_html($content['last_update']).'</td>
						<td style="color:#dc3545;">'.esc_html($content['loss']).'</td>
						<td style="color:#dc3545;">'.esc_html($content['drop_percent']).'</td>
						<td><span class="'.esc_attr($badge_class).'">'.esc_html($content['performance_score']).'</span></td>
					</tr>';
				}
				
				if(empty($content_ranking) && !$data['is_sample']){
					echo'<tr><td colspan="6" style="text-align:center;">'.esc_html__('No data available yet', 'siteseo').'</td></tr>';
				}
				
				echo'</tbody></table>';
			
			// Pagination controls
			if($total_pages > 1){
				echo'<div class="siteseo-pagination" style="margin-top: 20px; text-align: center;">';
				
				// Previous btn
				if($current_page > 1){
					echo'<a href="'.esc_url(add_query_arg('cr_page', $current_page - 1)).'" class="siteseo-option btnSecondary">'.esc_html__('Previous', 'siteseo').'</a> ';
				}
				
				// Page numbers
				for($i = 1; $i <= $total_pages; $i++){
					if($i == $current_page){
						echo'<span class="siteseo-option btnSecondary" style="margin: 0 2px;">'.esc_html($i).'</span> ';
					} else{
						echo'<a href="'.esc_url(add_query_arg('cr_page', $i)).'" class="siteseo-option btnSecondary" style="margin: 0 2px;">'.esc_html($i).'</a> ';
					}
				}
				
				// Next btn
				if($current_page < $total_pages){
					echo'<a href="'.esc_url(add_query_arg('cr_page', $current_page + 1)).'" class="siteseo-option btnSecondary">'.esc_html__('Next', 'siteseo').'</a>';
				}
				
				echo'</div>';
			}
			
			echo'</div>';
		}
	}

	static function audience_tab(){
		self::connect_notices();
		$data = self::fetch_data();
		$country_data = $data['country_data'];
		$device_data = $data['device_data'];

		echo'<div class="siteseo-audience-statisc">
			<div class="siteseo-stats-container">
				<h2 class="siteseo-stat-title">'.esc_html__('Device breakdown', 'siteseo').'</h2>
				 <hr class="siteseo-stats-separator">
				 <canvas id="siteseo_device_statics" height="250px" width="520px" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
			</div>
			
			<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Top countries by click ( Top 5 )', 'siteseo').'</h2>
				<hr class="siteseo-stats-separator">
				<canvas id="siteseo_country_statics" height="300px" width="520px" data-sample="'.($data['is_sample'] ? '1' : '0').'"></canvas>
			</div>
		</div>';

		if(!empty($device_data) || $data['is_sample']){
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Device Performance', 'siteseo').'</h2>
					<table class="wp-list-table widefat fixed striped siteseo-history-table">
						<thead><tr>
							<th>'.esc_html__('Device', 'siteseo').'</th>
							<th>'.esc_html__('Clicks', 'siteseo').'</th>
							<th>'.esc_html__('Impressions', 'siteseo').'</th>
						</tr>
						</thead>
					<tbody>';
					
					foreach($device_data as $data){
						echo'<tr>
							<td style="font-weight:bold;">'.esc_html( is_array($data['device']) ? implode(', ', $data['device']) : $data['device']).'</td>
							<td>'.esc_html($data['clicks']).'</td>
							<td>'.esc_html($data['impressions']).'</td>
						</tr>';
					}
					
				echo'</tbody></table>
			</div>';
		}

		if(!empty($country_data) || $data['is_sample']){
			echo'<div class="siteseo-stats-container">
				<h2 class="siteseo-stats-title">'.esc_html__('Country Performance ( Top 5 )', 'siteseo').'</h2>
					<table class="wp-list-table widefat fixed striped siteseo-history-table">
						<thead><tr>
							<th>'.esc_html__('Country', 'siteseo').'</th>
							<th>'.esc_html__('Clicks', 'siteseo').'</th>
							<th>'.esc_html__('Impressions', 'siteseo').'</th>
						</tr>
						</thead>
					<tbody>';
					
					foreach($country_data as $data){
						echo '<tr>
							<td style="font-weight:bold;">'.esc_html($data['country']).'</td>
							<td>'.esc_html($data['clicks']).'</td>
							<td>'.esc_html($data['impressions']).'</td>
						</tr>';
					}
					
					echo'</tbody></table>
				</div>';
		}
	}
	
	static function connect_notices(){
		
		$analytics_data = '';
		$gsc_connected = '';
		
		if(class_exists('\SiteSEOPro\GoogleConsole') && method_exists('\SiteSEOPro\GoogleConsole', 'is_connected')){
			$analytics_data = get_option('siteseo_search_console_data', []);

			$gsc_connected = \SiteSEOPro\GoogleConsole::is_connected();
		}
		
		 if(empty($gsc_connected)){
			
			echo'<div class="siteseo-notice is-warning"><p>'.wp_kses_post(__('The data shown here is only a <strong> sample from Google Analytics</strong> how SiteSEO will display your site\'s analytics once connected.', 'siteseo')).'</p>';

			if(class_exists('\SiteSEOPro\GoogleConsole')){
				echo'<form method="post">';
						wp_nonce_field('siteseo_pro_connect_google');
						echo '<input type="hidden" name="redirect_type" value="settings">
						<button type="submit" name="siteseo_pro_connect_btn" class="siteseo-statistics-connect-btn">'.esc_html__('Connect Search Console', 'siteseo') .'</button>
					</form>';
			} else{
				  echo'<a href="https://siteseo.io/pricing" class="siteseo-statistics-connect-btn" target="_blank">'.esc_html__('Buy Pro', 'siteseo').'</a>';
			}
			
			echo'</div>';
		} elseif(empty($analytics_data['top_pages']) && !empty($gsc_connected)){
			echo '<div class="siteseo-notice is-info"><p>'.wp_kses_post(__('Connected to Google Search Console. If this is your first time connecting the site and data doesn’t appear yet, please wait—Google may take a few days to populate the data. You can also try refreshing.', 'siteseo')).'</p></div>';
		}
	}

	static function sample_device_data(){
		 return [
			[
				'device' => 'Mobile',
				'clicks' => '48k',
				'impressions' => '285k',
				'ctr' => '5.2%',
			],
			[
				'device' => 'Desktop',
				'clicks' => '70k',
				'impressions' => '196k',
				'ctr' => '3.8%',
			],
			[
			
				'device' => 'Tablet',
				'clicks' => '10k',
				'impressions' => '185k',
				'ctr' => '8.1%',
			],
		];
	}

	static function sample_country_data(){
		
		 return [
			[
				'country' => 'India',
				'clicks' => '8K',
				'impressions' => '154K',
				'ctr' => '5.2%',
			],
			[
				'country' => 'Poland',
				'clicks' => '5K',
				'impressions' => '132K',
				'ctr' => '3.8%',
			],
			[
			
				'country' => 'South Africa',
				'clicks' => '15K',
				'impressions' => '185k',
				'ctr' => '8.1%',
			],
			[
				'country' => 'Russia',
				'clicks' => '19K',
				'impressions' => '200k',
				'ctr' => '9.5%',
			],
			[
				'country' => 'United kingdom',
				'clicks' => '12K',
				'impressions' => '150k',
				'ctr' => '5.5%',
			],
		];
		
	}
	
	static function sample_metrics_data(){
		return [
			'impressions' => [
				'current' => '15M',
				'change' => '-475.7K',
				'trend' => 'negative',
				'chart_data' => [12, 19, 3, 5, 2, 3, 10, 8, 12, 14, 13, 15]
			],
			'clicks' => [
				'current' => '111.5K',
				'change' => '+1.7K',
				'trend' => 'positive',
				'chart_data' => [7, 11, 5, 8, 3, 7, 4, 5, 6, 7, 6, 8]
			],
			'ctr' => [
				'current' => '0.74%',
				'change' => '+0.03%',
				'trend' => 'positive',
				'chart_data' => [0.5, 0.6, 0.7, 0.65, 0.75, 0.7, 0.6, 0.7, 0.72, 0.74, 0.73, 0.75]
			],
			'position' => [
				'current' => '49',
				'change' => '+1',
				'trend' => 'negative',
				'chart_data' => [55, 50, 45, 50, 48, 52, 55, 50, 49, 47, 48, 49]
			]
		];
	}

	static function sample_top_pages(){
		return [
			[
				'title' => '/blog/',
				'truseo_score' => '95',
				'indexed' => true,
				'clicks' => '4.5K',
				'impressions' => '57.2K',
				'position' => '23',
				'diff' => '+2'
			],
			[
				'title' => '/contact-us/',
				'truseo_score' => '88',
				'indexed' => false,
				'clicks' => '1.2K',
				'impressions' => '1.2M',
				'position' => '40',
				'diff' => '-5'
			],
			[
				'title' => '/support/',
				'truseo_score' => '92',
				'indexed' => false,
				'clicks' => '15K',
				'impressions' => '1.9M',
				'position' => '16',
				'diff' => '+3'
			],
			[
				'title' => '/pricing/',
				'truseo_score' => '85',
				'indexed' => true,
				'clicks' => '8.7K',
				'impressions' => '890K',
				'position' => '12',
				'diff' => '+1'
			],
			[
				'title' => '/features/',
				'truseo_score' => '90',
				'indexed' => true,
				'clicks' => '12.3K',
				'impressions' => '1.5M',
				'position' => '8',
				'diff' => '+4'
			]
		];
	}

	static function sample_keywords(){
		return [
			[
				'keyword' => 'One click seo plugin',
				'clicks' => '8K',
				'ctr' => '5.2%',
				'impressions' => '154K',
				'position' => '3',
				'trend' => 'up',
				'points' => '90'
			],
			[
				'keyword' => 'wordpress seo',
				'clicks' => '5K',
				'ctr' => '3.8%',
				'impressions' => '132K',
				'position' => '7',
				'trend' => 'up',
				'points' => '80'
			],
			[
				'keyword' => 'best seo plugin plugin',
				'clicks' => '15K',
				'ctr' => '8.1%',
				'impressions' => '185K',
				'position' => '2',
				'trend' => 'up',
				'points' => '85'
			],
			[
				'keyword' => 'seo optimization',
				'clicks' => '3.2K',
				'ctr' => '2.1%',
				'impressions' => '152K',
				'position' => '15',
				'trend' => 'down',
				'points' => '88'
			],
			[
				'keyword' => 'website ranking',
				'clicks' => '6.8K',
				'ctr' => '4.5%',
				'impressions' => '151K',
				'position' => '5',
				'trend' => 'up',
				'points' => '70'
			]
		];
	}
	
	static function sample_content_ranking(){
		return [
			[
				'title' => 'Ultimate SEO Guide 2024',
				'indexed' => 'Yes',
				'last_update' => '2024-01-15',
				'loss' => '2.1K',
				'drop_percent' => '5.2%',
				'performance_score' => '88'
			],
			[
				'title' => 'WordPress Optimization Tips',
				'indexed' => 'Yes',
				'last_update' => '2024-01-10',
				'loss' => '1.5K',
				'drop_percent' => '3.8%',
				'performance_score' => '92'
			],
			[
				'title' => 'Mobile SEO Strategies',
				'indexed' => 'No',
				'last_update' => '2024-01-08',
				'loss' => '3.2K',
				'drop_percent' => '8.1%',
				'performance_score' => '75'
			],
			[
				'title' => 'Content Marketing Guide',
				'indexed' => 'Yes',
				'last_update' => '2024-01-12',
				'loss' => '0.8K',
				'drop_percent' => '2.1%',
				'performance_score' => '95'
			]
		];
	}

	static function connect_site_dialogbox(){

		$gsc_sites = '';
		$current_site_url = trailingslashit(get_site_url());

		if(class_exists('\SiteSEOPro\GSCSetup') && method_exists('\SiteSEOPro\GSCSetup', 'get_pre_connected_sites')){
			$gsc_sites = \SiteSEOPro\GSCSetup::get_pre_connected_sites();
		}

		$current_site_exists = false;
		if(!empty($gsc_sites) && !isset($gsc_sites['error'])){
			foreach($gsc_sites as $site){
				if($site['siteUrl'] === $current_site_url){
					$current_site_exists = true;
					break;
				}
			}
		}

		echo'<div id="siteseo-site-connection-dialog" title="'.esc_attr__('Connect site search console', 'siteseo').'" style="display:none;">
			<div class="siteseo-dialog-content">';

		echo'<div id="siteseo-main-section">';

		if($current_site_exists){
			// Tab: Current Site
			echo'<div class="siteseo-option-primary" style="margin-bottom:20px;">
				<p style="color:#1d2327;font-weight:400;font-size:14px;">'.esc_html__('This site is already in your Google Search Console account.', 'siteseo').'</p>
				<div class="siteseo-form-group">
					<input type="text" id="siteseo-site-url" value="' . esc_attr($current_site_url) . '" class="regular-text" readonly
						style="width:100%;padding:8px;background:#f6f7f7;border:1px solid #8c8f94;color:#666;cursor:not-allowed;" />
				</div>
				<div class="siteseo-dialog-actions">
					<button type="button" class="button button-primary siteseo-action-btn" id="siteseo-connect-existing">'.esc_html__('Connect', 'siteseo').'</button>
					<span class="spinner"></span>
				</div>
			</div>';
			if(!empty($gsc_sites)){
				echo '<div class="siteseo-option-secondary">
					<button type="button" class="button button-link" id="siteseo-show-existing-properties" style="width:100%;text-decoration:none;">'.esc_html__('Select from existing sites', 'siteseo').'</button>
				</div>';
			}
		} else{
			// Not connected yet
			echo'<div class="siteseo-option-primary" style="margin-bottom:20px;">
				<p style="color:#1d2327;font-weight:400;font-size:14px;">'.esc_html__('This domain isn\'t yet connected to Google Search Console.', 'siteseo').'</p>
				<div class="siteseo-form-group">
					<input type="text" id="siteseo-new-domain-url" value="' . esc_attr($current_site_url) . '" class="regular-text" readonly
						style="width:100%;padding:8px;background:#f6f7f7;border:1px solid #8c8f94;color:#666;cursor:not-allowed;" />
				</div>
				<button type="button" class="button button-primary siteseo-action-btn siteseo-create-btn" id="siteseo-create-gsc-property" style="margin-bottom:10px;">'.esc_html__('Connect New Domain', 'siteseo').'</button>
				<span class="spinner"></span>
			</div>';

			if(!empty($gsc_sites)){
				echo'<div class="siteseo-option-secondary">
					<button type="button" class="button button-link" id="siteseo-show-existing-properties" style="width:100%;text-decoration:none;">'.esc_html__('Connect with existing properties', 'siteseo').'</button>
				</div>';
			}
		}

		echo'</div>';

		if(!empty($gsc_sites) && !isset($gsc_sites['error'])){
			echo'<div id="siteseo-existing-properties-section" style="display:none;">
				<p style="color:#1d2327;font-weight:400;font-size:14px;">'. esc_html__('Select an existing site from your Google Search Console account.', 'siteseo').'</p>
				<div class="siteseo-form-group">
					<select id="siteseo-site-url" name="existing_site_url" class="siteseo-select-box">';

						foreach($gsc_sites as $site){
							echo'<option value="'.esc_attr($site['siteUrl']).'">'.esc_html($site['siteUrl']).'</option>';
						}

			echo'</select>
				</div>
				<div class="siteseo-dialog-actions">
					<button type="button" class="button button-secondary siteseo-action-btn" id="siteseo-back-to-main">'.esc_html__('Back', 'siteseo').'</button>
					<button type="button" class="button button-primary siteseo-action-btn" id="siteseo-connect-existing">'.esc_html__('Connect', 'siteseo').'</button>
					<span class="spinner" style="margin-top:7px;"></span>
				</div>
			</div>';
		}

		echo'</div></div>'; // End dialog content + wrapper
	}
}
settings/titles.php000064400000134211151526415240010430 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Titles{

	static function menu(){
		global $siteseo;

		$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_siteseo_home'; // Default tab

		$titles_meta_subtabs = [
			'tab_siteseo_home' => esc_html__('Home', 'siteseo'),
			'tab_siteseo_post_types' => esc_html__('Post types', 'siteseo'),
			'tab_siteseo_archives' => esc_html__('Archives', 'siteseo'),
			'tab_siteseo_taxonomies' => esc_html__('Taxonomies', 'siteseo'),
			'tab_siteseo_advanced' => esc_html__('Advanced','siteseo')
		];

		echo '<div id="siteseo-root">';
		Util::admin_header();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';

		wp_nonce_field('siteseo_title_settings');

		$titles_meta_toggle = isset($siteseo->setting_enabled['toggle-titles']) ? $siteseo->setting_enabled['toggle-titles'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		Util::render_toggle('Titles & Metas - SiteSEO', 'titles_meta_toggle', $titles_meta_toggle, $nonce);

		echo '<div id="siteseo-tabs" class="wrap">
		<div class="siteseo-nav-tab-wrapper">';
		
		foreach($titles_meta_subtabs as $tab_key => $tab_caption) {
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="' . esc_attr($tab_key) . '-tab" class="siteseo-nav-tab' . esc_attr($active_class) . '" data-tab="' . esc_attr($tab_key) . '">' . esc_html($tab_caption) . '</a>';
		}

		echo '</div>     
		<div class="tab-content-wrapper">
		<div class="siteseo-tab '.($current_tab == 'tab_siteseo_home' ? ' active' : '').'" id="tab_siteseo_home" style="display: none;">';
		self::home();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_siteseo_post_types' ? ' active' : '').'" id="tab_siteseo_post_types" style="display: none;">';
		self::post_types();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_siteseo_archives' ? ' active' : '').'" id="tab_siteseo_archives" style="display: none;">';
		self::archives();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_siteseo_taxonomies' ? ' active' : '').'" id="tab_siteseo_taxonomies" style="display: none;" style="display: none;">';
		self::taxonomies();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_siteseo_advanced' ? ' active' : '').'" id="tab_siteseo_advanced">';
		self::advanced(); 
		echo '</div>
		</div>';
		Util::submit_btn();
		echo '</form></div>';

	}

    static function home(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		$options = get_option('siteseo_titles_option_name');
		//$options = $siteseo->titles_settings;

		$option_separator = !empty($options['titles_sep']) ? $options['titles_sep'] : '';
		$option_site_title = !empty($options['titles_home_site_title']) ? $options['titles_home_site_title'] : '';
		$option_site_title_alt = !empty($options['titles_home_site_title_alt']) ? $options['titles_home_site_title_alt'] : '';
		$option_site_desc = !empty($options['titles_home_site_desc']) ? $options['titles_home_site_desc'] : '';

		if(get_option('show_on_front') === 'page'){
			$front_page_id = get_option('page_on_front');
			$edit_link = get_edit_post_link($front_page_id, '');
			
			echo'<div class="siteseo_wrap_label">
				<div class="siteseo-notice is-warning">
					<span id="dashicons-warning" class="dashicons dashicons-info"></span>&nbsp;
					<p>'. // translators: %s is the platform name
					wp_kses_post(sprintf(__('A static page is set as your site front page <strong>(%s Dashboard > Settings > Reading)</strong>. To add an SEO title, description, and meta tags for the homepage, please click here -', 'siteseo'), !defined('SITEPAD') ? 'WP' : 'Sitepad')) . '</p>
					<div>
						<a href="'.esc_url($edit_link).'" target="_blank">'.esc_html__('Edit Home Page', 'siteseo').'</a>
					</div>
				</div>
			</div>';
			return;
		}

		echo '<h3 class="siteseo-tabs">'.esc_html__('HOME','siteseo').'</h3>
		<div class="siteseo-notice">
			<span id="siteseo-dash-icon" class="dashicons dashicons-info"></span>&nbsp;
			<p>'.esc_html__('Search engines use the title and meta description to create a snippet of your site for the search results page.', 'siteseo').'</p>
		</div>

		<p>'.esc_html__('Personalize the title and meta description for your homepage.','siteseo').'</p>

		<span class="dashicons dashicons-external"></span>
		<a href="'.esc_attr('https://siteseo.io/docs/meta/google-uses-the-wrong-meta-title-meta-description-in-search-results/').'" target="_blank">'.esc_html__('Incorrect meta title or description appearing in search results?', 'siteseo').'</a>

		<table class="form-table">
			<tbody>
                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Separator','siteseo').'</th>
                    <td>
                        <input type="text" name="siteseo_options[separator]" placeholder="'.esc_attr__('Specify your separator, e.g:-','siteseo').'" value="'.esc_attr($option_separator).'">
                        <p class="description">'.esc_attr__('Include this separator using %%sep%% in your title and meta description.','siteseo').'</p>
                    </td>
                </tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Site title','siteseo').'</th>
                    <td>
                        <input type="text" name="siteseo_options[site_title]" value="'.esc_attr($option_site_title).'" placeholder="'.esc_html__('My fantastic site','siteseo').'">
                        <div class="wrap-tags">
                            <button class="tag-title-btn" id="btn-site-title" data-tag="%%sitetitle%%"><span id="icon" class="dashicons dashicons-insert"></span>'.
							esc_html__('SITE TITLE','siteseo').'</button>
                            <button class="tag-title-btn" id="btn-separator" data-tag="%%sep%%"><span id="icon" class="dashicons dashicons-insert"></span>'.
							esc_html__('SEPARATOR','siteseo').'</button>
                            <button class="tag-title-btn" id="btn-tagline" data-tag="%%tagline%%"><span id="icon" class="dashicons dashicons-insert"></span>'.
							esc_html__('TAGLINE','siteseo').'</button>';
							siteseo_suggestion_button();
                        echo '</div>
                    </td>
                </tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Alternative site title','siteseo').'</th>
                    <td>
                        <input type="text" value="'.esc_attr($option_site_title_alt).'"  name="siteseo_options[alt_site_title]" placeholder="'.esc_html__('Alternative website title','siteseo').'">
                        <p class="description">'.esc_html__('The alternative name of the website (e.g., a commonly recognized acronym or shorter name, if applicable). Ensure the name meets the criteria.', 'siteseo').'</p>
                    </td>
                </tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Meta description','siteseo').'</th>
                    <td>
                        <textarea type="text" name="siteseo_options[media_desc]" placeholder="'.esc_html__('This is an awesome website about galactic creatures.','siteseo').'">'.esc_html($option_site_desc).'</textarea>
                        <div class="wrap-tags">
                            <button class="tag-title-btn" id="btn-tagline-meta" data-tag="%%tagline%%"><span id="icon" class="dashicons dashicons-insert"></span>'.
							esc_html__('TAGLINE','siteseo').'</button>';
                            siteseo_suggestion_button();  
                       echo '</div>
                    </td>
                </tr>
            </tbody>
        </table>
		<input type="hidden" name="siteseo_options[home_tab]" value="1"/>';
    }

    static function advanced(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

        //$options = $siteseo->titles_settings;
		$options = get_option('siteseo_titles_option_name');

		$option_noindex = !empty($options['titles_noindex']) ? $options['titles_noindex'] : '';
		$option_nofollow = !empty($options['titles_nofollow']) ? $options['titles_nofollow'] : '';
		$option_noimage = !empty($options['titles_noimageindex']) ? $options['titles_noimageindex'] : '';
		$option_noarchive = !empty($options['titles_noarchive']) ? $options['titles_noarchive'] : '';
		$option_nosnippet = !empty($options['titles_nosnippet']) ? $options['titles_nosnippet'] : '';
		$option_nositelinkssearchbox = !empty($options['titles_nositelinkssearchbox']) ? $options['titles_nositelinkssearchbox'] : '';
		$option_page_rel = !empty($options['titles_paged_rel']) ? $options['titles_paged_rel'] : '';
		$option_paged_noindex = !empty($options['titles_paged_noindex']) ? $options['titles_paged_noindex'] : '';
		$option_attachments_noindex = !empty($options['titles_attachments_noindex']) ? $options['titles_attachments_noindex'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Advanced','siteseo').'</h3>
		<p>'.esc_html__('Customize your metas for all pages','siteseo').'</p>

		<table class="form-table">
			<tbody>
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('noindex','siteseo').'</th>
					<td>
						<label>
						<input name="siteseo_options[noindex]" type="checkbox" '.(!empty($option_noindex) ? 'checked="yes"' : '') . ' value="1"/>' . esc_html__('noindex', 'siteseo') . 
						'</label>
						<p class="description">'.esc_attr__('Do not show all pages of the site in Google search results and avoid displaying "Cached" links in search results.','siteseo').'</p>
						'.wp_kses_post('<p class="description">Check also the<strong>"Search engine visibility"</strong> setting from the <a href="%s">WordPress Reading page</a></p>').'
					</td>
				</tr>

				<td colspan="2"><span class="dashed-line"></span></td>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('nofollow','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[no_follow]" type="checkbox"'.(!empty($option_nofollow) ? 'checked="yes"' : '') . ' value="1"/>'. esc_html__('nofollow', 'siteseo'). 
						'</label>
						<p class="description">'.esc_html__('Do not follow links on all pages.','siteseo').'</p>
					</td>
				<tr>

				<td colspan="2"><span class="dashed-line"></span></td>
					
					<tr>
						<th scope="row" style="user-select:auto;">'.esc_html__('noimageindex','siteseo').'</th>
						<td>
							<label>
								<input name="siteseo_options[no_image]" type="checkbox"'.(!empty($option_noimage) ? 'checked="yes"' : '').' value="1"/>'. esc_html__('noimageindex', 'siteseo'). 
							'</label>
							<p class="description">'.esc_html__('Do not follow links on any pages.','siteseo').'</p>
						</td>
					<tr>

				<td colspan="2"><span class="dashed-line"></span></td>

					<tr>
						<th scope="row" style="user-select:auto;">'.esc_html__('noarchive','siteseo').'</th>
						<td>
							<label>
								<input name="siteseo_options[no_archive]" type="checkbox"'.(!empty($option_noarchive) ? 'checked="yes"' : '').' value="1"/>' . esc_html__('noarchive', 'siteseo'). 
							'</label>
							<p class="description">'.esc_html__('Do not show a "Cached" link in Google search results.','siteseo').'</p>
						</td>
					</tr>

				<td colspan="2"><span class="dashed-line"></span></td>

						<tr>
							<th scope="row" style="user-select:auto;">'.esc_html__('nosnippet','siteseo').'</th>
							<td>
								<label>
									<input name="siteseo_options[no_snippet]" type="checkbox"'.(!empty($option_nosnippet) ? 'checked="yes"' : '').' value="1"/>' . esc_html__('nosnippet', 'siteseo'). 
								'</label>
								<p class="description">'.esc_html__('Do not show a description in the Google search results for any pages.','siteseo').'</p>
							</td>
						</tr>

				<td colspan="2"><span class="dashed-line"></span></td>

						<tr>
							<th scope="row" style="user-select:auto;">'.esc_html__('nositelinkssearchbox','siteseo').'</th>
							<td>
								<label>
									<input name="siteseo_options[no_site_links_searchbox]" type="checkbox"'.(!empty($option_nositelinkssearchbox) ? 'checked="yes"' : ''). ' value="1"/>' . esc_html__('nositelinkssearchbox', 'siteseo') . 
								'</label>
								<p class="description">'.esc_html__('Prevents Google from displaying a sitelinks search box in search results. Enabling this option will remove the "Website" schema from your source code.','siteseo') .'</p>
							</td>
						</tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                 <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Indicate paginated content to Google','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[page_rel]" type="checkbox"' . (!empty($option_page_rel) ? 'checked="yes"' : '') . ' value="1"/>' . esc_html__('Add rel next/prev link in head of paginated archive pages', 'siteseo') . 
                        '</label>
                        <p class="description">'.esc_html__('eg: https://example.com/category/my-category/page/2/.','siteseo').'</p>
                    </td>
                </tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                 <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('noindex on paged archives','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[titles_paged_noindex]" type="checkbox" '. (!empty($option_paged_noindex) ? 'checked="yes"' : '') . ' value="1"/>'.esc_html__('Add a "noindex" meta robots for all paginated archive pages', 'siteseo'). 
                        '</label>
                        <p class="description">'.esc_html__('eg: https://example.com/category/my-category/page/2/.','siteseo').'</p>
                    </td>
                </tr>

                <td colspan="2"><span class="dashed-line"></span></td>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('noindex on attachment pages','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[attachments_noindex]" type="checkbox"' . (!empty($option_attachments_noindex) ? 'checked="yes"' : '').' value="1"/>'.esc_html__(' Add a "noindex" meta robots for all attachment pages', 'siteseo') . 
                        '</label>
                        <p class="description">'.esc_html__('eg: https://example.com/my-media-attachment-page.','siteseo').'</p>
                    </td>
                </tr>
            </tbody>
        </table><input type="hidden" name="siteseo_options[advanced_tab]" value="1"/>';
    }

	static function archives(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

        	// $options = $siteseo->titles_settings;
		$options = get_option('siteseo_titles_option_name');

        	// Load settings
		$option_author_title = !empty($options['titles_archives_author_title']) ? $options['titles_archives_author_title'] : '';
		$option_author_desc = !empty($options['titles_archives_author_desc']) ? $options['titles_archives_author_desc'] : '';
		$option_author_noindex = !empty($options['titles_archives_author_noindex']) ? $options['titles_archives_author_noindex'] : '';
		$option_author_disabled = !empty($options['titles_archives_author_disable']) ? $options['titles_archives_author_disable'] : '';
		$option_date_title = !empty($options['titles_archives_date_title']) ? $options['titles_archives_date_title'] : '';
		$option_date_desc = !empty($options['titles_archives_date_desc']) ? $options['titles_archives_date_desc'] : '';
		$option_date_noindex = !empty($options['titles_archives_date_noindex']) ? $options['titles_archives_date_noindex'] : '';
		$option_date_disabled = !empty($options['titles_archives_date_disable']) ? $options['titles_archives_date_disable'] : '';
		$option_search_title = !empty($options['titles_archives_search_title']) ? $options['titles_archives_search_title'] : '';
		$option_search_desc = !empty($options['titles_archives_search_desc']) ? $options['titles_archives_search_desc'] : '';
		$option_search_noindex = !empty($options['titles_archives_search_title_noindex']) ? $options['titles_archives_search_title_noindex'] : '';
		$option_404_title = !empty($options['titles_archives_404_title']) ? $options['titles_archives_404_title'] : '';
		$option_404_desc = !empty($options['titles_archives_404_desc']) ? $options['titles_archives_404_desc'] : '';
		$author_base_url = !empty($options['author_base_url']) ? $options['author_base_url'] : 'author';

		$archives_fields = [
			'author-archives' => 'Author archives',
			'date-archives'   => 'Date archives',
			'search-archives' => 'Search archives',
			'404-archives'    => '404 archives'
		];
		
		$post_types = siteseo_post_types();

		echo'<table class="form-table">
			<tbody>
				<tr>
					<th scope="row">
					<div class="siteseo-container">';
					$is_first = true;
					foreach($archives_fields as $post_key => $post_val){
						$active_class = $is_first ? 'active' : '';
						echo '<a href="-' . esc_attr($post_key) . '" class="' . esc_attr($active_class) . '">' . esc_html($post_val) . '</a>';
						$is_first = false;
					}

					foreach($post_types as $post_name => $post_type){
						if($post_type->has_archive){
							$active_class = $is_first ? 'active' : '';
							echo '<a href="-' . esc_attr($post_name) . '" class="' . esc_attr($active_class) . '">' . esc_html($post_type->label) . '</a>';
							$is_first = false;
						}
					}

					echo '</div>
					</th>
					<td>
					<div id="author-archives">
						<h3>'.esc_html__('Archives', 'siteseo').'</h3>
						<div class="siteseo_wrap_label">
							<p class="description">'.esc_html__('Personalize your meta descriptions for all archives.','siteseo').'</p>
						</div>
						<span class="line"></span>
						<h3>'.esc_html__('Author archives', 'siteseo').'</h3>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Title template', 'siteseo').'</p></div>
						<input type="text" name="siteseo_options[author_title]" value="'. esc_attr($option_author_title) . '">
    
						<div class="wrap-tags">
							<button class="tag-title-btn" id="btn-author-acrhive-title" data-tag="%%post_author%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('POST AUTHOR','siteseo').'
							</button>
							<button class="tag-title-btn" id="btn-author-acrhive-separator" data-tag="%%sep%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
							</button>
							<button class="tag-title-btn" id="btn-author-acrhive-sitetitle" data-tag="%%sitetitle%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
							</button>';
							siteseo_suggestion_button();
						echo '</div>
    
						<div class="siteseo_wrap_label"><p>Meta description template</p></div>
						<textarea name="siteseo_options[author_desc]">'.esc_html($option_author_desc) . '</textarea><br>
						<div class="siteseo_wrap_label">
							<label>
							<input name="siteseo_options[author_noindex]" type="checkbox" '.(!empty($option_author_noindex) ? 'checked="yes"' : '').' value="1"/>' . wp_kses_post('Do not display author archives in search engine results <strong>(noindex)</strong>') .'
							</label>
    
							<label>
							<input name="siteseo_options[author_disable]" type="checkbox" '.(!empty($option_author_disabled) ? 'checked="yes"' : '').' value="1"/>
							' . esc_html__('Disable author archives', 'siteseo') . '
							</label>
						</div>

						<div class="siteseo_wrap_label"><p style="font-weight: 500;">'.esc_html__('Author base', 'siteseo');
						if(!defined('SITESEO_PRO_VERSION')){
							echo'<span class="siteseo-pro-tag">Pro</span>';
						}

						echo'</p></div>
						<input type="text" name="siteseo_options[author_base]" value="' . esc_attr($author_base_url) . '" ' .(!defined('SITESEO_PRO_VERSION') ? 'disabled="disabled" style="cursor:not-allowed;"' : '').'>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Change the /author/ slug used in author archive URLs.', 'siteseo').'</p>

					</div>
    
					<div id="date-archives">
						<h3>'.esc_html__('Date archives', 'siteseo').'</h3>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Title template','siteseo').'</p></div>
							<input type="text" name="siteseo_options[date_title]" value="'. esc_attr($option_date_title) .'">
							<div class="wrap-tags">
								<button class="tag-title-btn" id="btn-date-archive" data-tag="%%archive_date%%">
									<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('DATE ARCHIVES','siteseo').'
								</button>
								<button class="tag-title-btn" id="btn-date-separator" data-tag="%%sep%%">
									<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
								</button>
								<button class="tag-title-btn" id="btn-date-sitetitle" data-tag="%%sitetitle%%">
									<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
								</button>';
								siteseo_suggestion_button();
							echo '</div>
    
						<div class="siteseo_wrap_label"><p>'.esc_html__('Meta description template','siteseo').'</p></div>
						<textarea name="siteseo_options[date_desc]">'.esc_attr($option_date_desc).'</textarea><br>
						<div class="siteseo_wrap_label">
							<label>
							<input name="siteseo_options[date_noindex]" type="checkbox" '.(!empty($option_date_noindex) ? 'checked="yes"' : '').' value="1"/>' . wp_kses_post('Do not display date archives in search engine results <strong>(noindex)</strong>') . '
							</label>

							<label>
							<input name="siteseo_options[date_disable]" type="checkbox" '.(!empty($option_date_disabled) ? 'checked="yes"' : '').' value="1"/>
							' . esc_html__('Disable date archives', 'siteseo') . '
							</label>
						</div>
						<span class="line"><span>
					</div>
						
					<div id="search-archives">
						<h3>Search archives</h3>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Title template','siteseo').'</p></div>
						<input type="text" name="siteseo_options[search_title]" value="'.esc_attr($option_search_title).'">

						<div class="wrap-tags">
							<button class="tag-title-btn" id="btn-search-keyword" data-tag="%%search_keywords%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEARCH KEYWORDS','siteseo').'
							</button>
							<button class="tag-title-btn"  id="btn-search-separator" data-tag="%%sep%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
							</button>
							<button class="tag-title-btn" id="btn-search-sitetitle" data-tag="%%sitetitle%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
							</button>';
							siteseo_suggestion_button();
						echo '</div>

						<div class="siteseo_wrap_label"><p>'.esc_html__('Meta description template','siteseo').'</p></div>
						<textarea name="siteseo_options[search_desc]">'.esc_attr($option_search_desc).'</textarea><br>
						<div class="siteseo_wrap_label">
							<label>
							<input name="siteseo_options[search_noindex]" type="checkbox" '.(!empty($option_search_noindex) ? 'checked="yes"' : '').' value="1"/>
							' . wp_kses_post('Do not display date archives in search engine results <strong>(noindex)</strong>') . '
							</label>
						</div>
						<span class="line"><span>
					</div>
						
					<div id="404-archives">
						<h3>404 archives</h3>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Title template','siteseo').'</p></div>
						<input type="text" name="siteseo_options[title_404]" value="'.esc_attr($option_404_title).'">

						<div class="wrap-tags">
							<button class="tag-title-btn" id="btn-404-sitetitle" data-tag="%%sep%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
							</button>
							<button class="tag-title-btn" id="btn-404-separator" data-tag="%%sitetitle%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
							</button>';
						siteseo_suggestion_button();
						echo '</div>

						<div class="siteseo_wrap_label"><p>'.esc_html__('Meta description template','siteseo').'</p></div>
						<textarea name="siteseo_options[desc_404]">'.esc_attr($option_404_desc).'</textarea><br>
					</div>
					<br/><br/>
					<span class="line"></span>';

				foreach($post_types as $post_name => $post_type){
					if(empty($post_type->has_archive)){
						continue;
					}

					$post_data = isset($options['titles_archive_titles'][$post_name]) ? $options['titles_archive_titles'][$post_name] : '';

					$archive_title = !empty($post_data['archive_title'])? $post_data['archive_title'] : '';
					$archive_description = !empty($post_data['archive_desc']) ? $post_data['archive_desc'] : '';
					$archive_noindex = !empty($post_data['archive_noindex']) ? $post_data['archive_noindex'] : '';
					$archive_nofollow = !empty($post_data['archive_nofollow']) ? $post_data['archive_nofollow'] : '';

					$value_check = !empty($options['titles_archive_titles'][$post_name]['archive_title']) ? $options['titles_archive_titles'][$post_name]['archive_title'] : '';

					echo'<div id="'.esc_attr($post_name).'">
						<h3>'.esc_html($post_type->label).'</h3>
						<div class="siteseo_wrap_label"><p>'.esc_html__('Title template','siteseo').'</p></div>
						<input type="text" name="siteseo_options['.esc_attr($post_name).'][archive_title]" value="'.esc_attr($archive_title).'">

						<div class="wrap-tags">
							<button class="tag-title-btn" data-tag="%%cpt_plural%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('POST TYPE ARCHIVE NAME','siteseo').'
							</button>
							<button class="tag-title-btn" data-tag="%%sep%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
							</button>
							<button class="tag-title-btn" data-tag="%%sitetitle%%">
								<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
							</button>';
						   siteseo_suggestion_button();
						echo'</div>

						<div class="siteseo_wrap_label"><p>'.esc_html__('Meta description template','siteseo').'</p></div>
						<textarea name="siteseo_options['.esc_attr($post_name).'][archive_desc]">'.esc_attr($archive_description).'</textarea><div class="wrap-tags">';
						siteseo_suggestion_button();
					echo'</div></div><br>
					<div class="siteseo_wrap_label">
						<label>
						<input name="siteseo_options['.esc_attr($post_name).'][archive_noindex]" type="checkbox" '.(!empty($archive_noindex) ? 'checked="yes"' : '').' value="1"/>
						' . wp_kses_post('Do not display author archives in search engine results <strong>(noindex)</strong>') .'
						</label><br/><br/>
						<label>
						<input name="siteseo_options['.esc_attr($post_name).'][archive_nofollow]" type="checkbox" '.(!empty($archive_nofollow) ? 'checked="yes"' : 'value="1"').' />'.wp_kses_post(__('Do not follow links for this taxonomy archive<strong>(nofollow)</strong>', 'siteseo')).'
						</label>
					</div><span class="line"><span>';
				}
	                    echo'</td>
	                </tr>
	            </tbody>
	        </table>
	        <input type="hidden" name="siteseo_options[archives_tab]" value="1"/>';
	}
    

    static function post_types(){
        global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		$options = get_option('siteseo_titles_option_name');
		$post_types = siteseo_post_types();

        echo '<table class="form-table">
                <tbody>
                    <tr>
                        <th scope="row">
                            <div class="siteseo-container">';
                                $is_first = true;
                                foreach($post_types as $post_type => $post_arr){
                                    $active_class = $is_first ? 'active' : '';
                                    echo '<a href="#'.esc_attr($post_type).'-types" class="'.esc_attr($active_class).'">'.esc_html($post_arr->labels->name).'</a>';
                                    $is_first = false;
                                }
                        echo '</div>
                        </th><td>
						<div>
							<h3>'.esc_html__('Post Types', 'siteseo').'</h3>
						   <div class="siteseo_wrap_label"><p class="description">'.esc_html__('Personalize your titles and meta descriptions for single custom post types.', 'siteseo').'</p></div>
						</div>';

		foreach($post_types as $post_type => $post_arr){
			// Load array
			$post_data = isset($options['titles_single_titles'][$post_type]) ? $options['titles_single_titles'][$post_type] : '';

			// Load settings
			$option_post_disabled = !empty($post_data['disabled']) ? true : false;
			$option_post_title = !empty($post_data['title']) ? $post_data['title'] : '';
			$option_post_desc = !empty($post_data['description']) ? $post_data['description'] : '';
			$option_noindex = !empty($post_data['noindex']) ? $post_data['noindex'] : '';
			$option_nofollow = !empty($post_data['nofollow']) ? $post_data['nofollow'] : '';
			$option_date = !empty($post_data['date']) ? $post_data['date'] : '';
			$option_thumb_gcs = !empty($post_data['thumb_gcs']) ? $post_data['thumb_gcs'] : '';

			echo '<div id="'.esc_attr($post_type).'-types">';
				echo '<div class="siteseo-toggle-cnt">
						<h3>'.esc_html($post_arr->labels->name.' ['.$post_type.']').'</h3>&nbsp;&nbsp;
						<div class="siteseo-toggle-meta '.($option_post_disabled ? '' : 'active').'" id="siteseo-toggle-meta-'.esc_attr($post_type).'"></div>
						<span id="siteseo-arrow-icon" class="dashicons dashicons-arrow-left-alt siteseo-arrow-icon"></span>
						<p class="toggle_state_posts" id="toggle_state_'.esc_attr($post_type).'">'.(!$option_post_disabled ? ' Click to hide any SEO metaboxes / columns for this post type' : ' Click to show any SEO metaboxes / columns for this post type').'</p>
						<input type="hidden" name="siteseo_options['.esc_attr($post_type).'][disabled]" id="enable_'.esc_attr($post_type).'_toggle" value="'.esc_attr($option_post_disabled).'" class="siteseo-suboption-toggle">
					</div>
					
					<div class="siteseo_wrap_label"><p>'.esc_html__('Title template', 'siteseo').'</p></div>
					<input type="text" name="siteseo_options['.esc_attr($post_type).'][title]" value="'.esc_attr($option_post_title).'">
					<div class="wrap-tags">
						<button class="tag-title-btn" id="btn-post-title" data-tag="%%post_title%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('POST TITLE', 'siteseo').'
						</button>
						<button class="tag-title-btn" id="btn-post-separator" data-tag="%%sep%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR', 'siteseo').'
						</button>
						<button class="tag-title-btn" id="btn-post-site-title" data-tag="%%sitetitle%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE', 'siteseo').'
						</button>';
						siteseo_suggestion_button();
					echo '</div>
					<div class="siteseo_wrap_label"><p class="description">'.esc_html__('Meta description template', 'siteseo').'</p></div>
					<textarea name="siteseo_options['.esc_attr($post_type).'][desc]">'.esc_attr($option_post_desc).'</textarea>
					<div class="wrap-tags">
						<button class="tag-title-btn" id="btn-'.esc_attr($post_type).'-meta" data-tag="%%post_excerpt%%">
							<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('POST EXCERPT', 'siteseo').'
						</button>';
						siteseo_suggestion_button();
					echo '</div>
					<div class="siteseo_wrap_label">
						<label>
							<input name="siteseo_options['.esc_attr($post_type).'][noindex]" type="checkbox" '.(!empty($option_noindex) ? 'checked="yes"' : 'value="1"').' />
							'.wp_kses_post(__('Do not display this single post type in search engine results <strong>(noindex)</strong>', 'siteseo')).'
						</label>
					</div>';
					
					if(!empty($option_noindex)){
						echo '<div class="siteseo_wrap_label">
							<div class="siteseo-notice is-error">
								<p>'.wp_kses_post(__('This custom post type is <strong>NOT</strong> excluded from your XML sitemaps despite the fact that it is set to <strong>NOINDEX</strong>.', 'siteseo')).'
								</p>
							</div>
						</div>';
					}
					
					echo '<div class="siteseo_wrap_label">
						<label>
							<input name="siteseo_options['.esc_attr($post_type).'][nofollow]" type="checkbox" '.(!empty($option_nofollow) ? 'checked="yes"' : 'value="1"').' />
							'.wp_kses_post(__('Do not follow links for this single post type <strong>nofollow</strong>', 'siteseo')).'
						</label>
					</div>
					<div class="siteseo_wrap_label">
						<label>
							<input name="siteseo_options['.esc_attr($post_type).'][date]" type="checkbox" '.(!empty($option_date) ? 'checked="yes"' : 'value="1"').' />
							'.esc_html__('Display date in Google search results by adding article:published_time and article:modified_time meta?', 'siteseo').'
						</label>
						<p class="description">'. esc_html__('Unchecking this does not prevent Google from displaying the post date in search results.', 'siteseo').'</p>
					</div>
					<div class="siteseo_wrap_label">
						<label>
							<input name="siteseo_options['.esc_attr($post_type).'][thumb_gcs]" type="checkbox" '.(!empty($option_thumb_gcs) ? 'checked="yes"' : 'value="1"').' />
							'.esc_html__('Display post thumbnail in Google Custom Search results?', 'siteseo').'
						</label>
						<p class="description">'.esc_html__('This option does not apply to traditional search results.', 'siteseo').'</p>
					</div>
				</div>';
		}
                    echo '</td></tr>
                </tbody>
            </table>
			<input type="hidden" name="siteseo_options[post_types_tab]" value="1"/>';
    }
    
    static function taxonomies(){
        global $siteseo;
 
        if(!empty($_POST['submit'])){
            self::save_settings();
        }

        // $options = $siteseo->titles_setting;
        $options = get_option('siteseo_titles_option_name');
		$taxonomies = get_taxonomies(['show_ui' => true, 'public'  => true], 'objects', 'and');

		echo '<table class="form-table">
			<tbody>
				<tr>
					<th scope="row">
						<div class="siteseo-container">';
							$is_first = true;
							foreach($taxonomies as $fields_key => $fields_val){
								$active_class = $is_first ? 'active' : '';
								echo '<a href="#'.esc_attr($fields_key).'-types" class="'.esc_attr($active_class).'">'.esc_html($fields_val->label).'</a>';
								$is_first = false;
							}
            echo '</th>
                    <td>
                        <h3>'.esc_html__('Taxonomies','siteseo').'</h3>
						<div class="siteseo_wrap_label">
                        <p class="description">'.esc_html__('Personalize your meta descriptions for all taxonomy archives.','siteseo').'</p>
						</div>';
		
		foreach($taxonomies as $taxonomy => $_tax){
			// Load array
			$options_tax = isset($options['titles_tax_titles'][$taxonomy]) ? $options['titles_tax_titles'][$taxonomy] : '';
			
			// Load settings
			$option_disabled_category = !empty($options_tax['disabled']) ? $options_tax['disabled'] : '';
			$option_cat_title = !empty($options_tax['title']) ? $options_tax['title'] : '';
			$option_cat_desc = !empty($options_tax['description']) ? $options_tax['description'] : '';
			$option_cat_noindex = !empty($options_tax['noindex']) ? $options_tax['noindex'] : '';
			$option_cat_nofollow = !empty($options_tax['nofollow']) ? $options_tax['nofollow'] : '';
	 
			$taxonomies_fields = [
				'categories-types' => 'Categories',
				'tags-types' => 'Tags',
			];

			echo '<div id="'.esc_attr($taxonomy).'-types"><h3>'.esc_html($_tax->label.'['.$taxonomy.']').'</h3>
				<div class="siteseo-toggle-cnt">
					<div class="siteseo-toggle-meta '.($option_disabled_category ? '' : 'active').'" id="siteseo-toggle-meta-category"></div>
					<span id="siteseo-arrow-icon" class="dashicons dashicons-arrow-left-alt siteseo-arrow-icon"></span>
					<p class="toggle_state_category" id="toggle_state_category">' .($option_disabled_category ? 'Enable' : 'Disable'). '</p>
					<input type="hidden" name="siteseo_options['.esc_attr($taxonomy).'][disabled]" id="enable_'.esc_attr($taxonomy).'" value="'.esc_attr($option_disabled_category).'" class="siteseo-suboption-toggle">
				</div>

				<div class="siteseo_wrap_label">
					<p class="description">'.esc_html__('Title template','siteseo').'</p>
				</div>
				<input type="text" value="'.esc_attr($option_cat_title).'" name="siteseo_options['.esc_attr($taxonomy).'][title]">
				<div class="wrap-tags">
					<button class="tag-title-btn" data-tag="%%_category_title%%">
						<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('CATEGORY TITLE','siteseo').'
					</button>
					<button class="tag-title-btn"  data-tag="%%sep%%">
						<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SEPARATOR','siteseo').'
					</button>
					<button class="tag-title-btn"  data-tag="%%sitetitle%%">
						<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('SITE TITLE','siteseo').'
					</button>';
						siteseo_suggestion_button(); 
				echo '</div>
				<div class="siteseo_wrap_label">
					<p class="description">Meta description template</p>
				</div>
				<textarea name="siteseo_options['.esc_attr($taxonomy).'][desc]">'.esc_attr($option_cat_desc).'</textarea>
				<div class="wrap-tags">
					<button class="tag-title-btn" data-tag="%%_category_description%%">
						<span id="icon" class="dashicons dashicons-insert"></span>'.esc_html__('CATEGORY DESCRIPTION','siteseo').'
					</button>';
					siteseo_suggestion_button();
				echo '</div>
				<div class="siteseo_wrap_label">
					<label>
						<input name="siteseo_options['.esc_attr($taxonomy).'][noindex]" type="checkbox" '.(!empty($option_cat_noindex) ? 'checked="yes"' : 'value="1"').' />
						'.wp_kses_post(__('Do not display this taxonomy archive in search engine results<strong>(noindex)</strong>', 'siteseo')).'
					</label>
				</div>';
				
				if(!empty($option_cat_noindex)){
					echo '<div class="siteseo_wrap_label">
						<div class="siteseo-notice is-error">
							<p>'.wp_kses_post(__('This custom taxonomy is <strong>NOT</strong> excluded from your XML sitemaps despite the fact that it is set to <strong>NOINDEX</strong>. We recommend that you check this out.', 'siteseo')).'
							</p>
						</div>
					</div>';
				}
				
				echo '<div class="siteseo_wrap_label">
					<label>
						<input name="siteseo_options['.esc_attr($taxonomy).'][nofollow]" type="checkbox" '.(!empty($option_cat_nofollow) ? 'checked="yes"' : 'value="1"').' />
						'.wp_kses_post(__('Do not follow links for this taxonomy archive<strong>(nofollow)</strong>', 'siteseo')).'
					</label>
				</div>
			</div>';
		}
                    echo '</td>
                </tr>
            </tbody>
        </table>
        <input type="hidden" name="siteseo_options[taxonomies_tab]" value="1"/>';
    }
    

    static function save_settings(){
        global $siteseo;
		
		check_admin_referer('siteseo_title_settings');

		if(!siteseo_user_can('manage_title') || !is_admin()){
			return;
		}

		$options = [];

		if(empty($_POST['siteseo_options'])){
			return;
		}

        if(isset($_POST['siteseo_options']['home_tab'])){
            
            $options['titles_sep'] = isset($_POST['siteseo_options']['separator']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['separator'])) : '';
			$options['titles_home_site_title'] = isset($_POST['siteseo_options']['site_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['site_title'])) : '';
			$options['titles_home_site_title_alt'] = isset($_POST['siteseo_options']['alt_site_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['alt_site_title'])) : '';
			$options['titles_home_site_desc'] = isset($_POST['siteseo_options']['media_desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['media_desc'])) : '';
        }

        if(isset($_POST['siteseo_options']['advanced_tab'])){

            $options['titles_noindex'] = isset($_POST['siteseo_options']['noindex']);
			$options['titles_nofollow'] = isset($_POST['siteseo_options']['no_follow']);
			$options['titles_noimageindex'] = isset($_POST['siteseo_options']['no_image']);
			$options['titles_noarchive'] = isset($_POST['siteseo_options']['no_archive']);
            $options['titles_nosnippet'] = isset($_POST['siteseo_options']['no_snippet']);
            $options['titles_nositelinkssearchbox'] = isset($_POST['siteseo_options']['no_site_links_searchbox']);
            $options['titles_paged_rel'] = isset($_POST['siteseo_options']['page_rel']);
            $options['titles_paged_noindex'] = isset($_POST['siteseo_options']['titles_paged_noindex']);
            $options['titles_attachments_noindex'] = isset($_POST['siteseo_options']['attachments_noindex']);

        }

        if(isset($_POST['siteseo_options']['post_types_tab'])){
			
			$post_types = siteseo_post_types();
			$post_types = array_keys($post_types);

			// Saving Posts
			foreach($post_types as $post_type){
				$options['titles_single_titles'][$post_type]['disabled'] = !empty($_POST['siteseo_options'][$post_type]['disabled']) ? true : false;
				$options['titles_single_titles'][$post_type]['title'] = isset($_POST['siteseo_options'][$post_type]['title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$post_type]['title'])) : '';
				$options['titles_single_titles'][$post_type]['description'] = isset($_POST['siteseo_options'][$post_type]['desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$post_type]['desc'])) : '';
				$options['titles_single_titles'][$post_type]['noindex'] = isset($_POST['siteseo_options'][$post_type]['noindex']);
				$options['titles_single_titles'][$post_type]['nofollow'] = isset($_POST['siteseo_options'][$post_type]['nofollow']);
				$options['titles_single_titles'][$post_type]['date'] = isset($_POST['siteseo_options'][$post_type]['date']);
				$options['titles_single_titles'][$post_type]['thumb_gcs'] = isset($_POST['siteseo_options'][$post_type]['thumb_gcs']);
			}
        }

        if(isset($_POST['siteseo_options']['archives_tab'])){
			
			$post_types = siteseo_post_types();
			$post_types = array_keys($post_types);
			
            $options['titles_archives_author_title'] = isset($_POST['siteseo_options']['author_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['author_title'])) : '';
			$options['titles_archives_author_desc'] = isset($_POST['siteseo_options']['author_desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['author_desc'])) : '';
			$options['titles_archives_author_noindex'] = isset($_POST['siteseo_options']['author_noindex']);
			$options['titles_archives_author_disable'] = isset($_POST['siteseo_options']['author_disable']);
            
			$options['titles_archives_date_title'] = isset($_POST['siteseo_options']['date_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['date_title'])) : '';
			$options['titles_archives_date_desc'] = isset($_POST['siteseo_options']['date_desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['date_desc'])) : '';
			$options['titles_archives_date_noindex'] = isset($_POST['siteseo_options']['date_noindex']);
			$options['titles_archives_date_disable'] = isset($_POST['siteseo_options']['date_disable']);
            
			$options['titles_archives_search_title'] = isset($_POST['siteseo_options']['search_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['search_title'])) : '';
			$options['titles_archives_search_desc'] = isset($_POST['siteseo_options']['search_desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['search_desc'])) : '';
			$options['titles_archives_search_title_noindex'] = isset($_POST['siteseo_options']['search_noindex']);
            
			$options['titles_archives_404_title'] = isset($_POST['siteseo_options']['title_404']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['title_404'])) : '';
			$options['titles_archives_404_desc'] = isset($_POST['siteseo_options']['desc_404'])  ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['desc_404'])) : '';
			
			foreach($post_types as $post_type){					
				$options['titles_archive_titles'][$post_type]['archive_title'] = isset($_POST['siteseo_options'][$post_type]['archive_title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$post_type]['archive_title'])) : '';
				$options['titles_archive_titles'][$post_type]['archive_desc'] = isset($_POST['siteseo_options'][$post_type]['archive_desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$post_type]['archive_desc'])) : '';
				$options['titles_archive_titles'][$post_type]['archive_noindex'] = isset($_POST['siteseo_options'][$post_type]['archive_noindex']);
				$options['titles_archive_titles'][$post_type]['archive_nofollow'] = isset($_POST['siteseo_options'][$post_type]['archive_nofollow']);
			}

        }

        if(isset($_POST['siteseo_options']['taxonomies_tab'])){
			$taxonomies = get_taxonomies(['show_ui' => true, 'public'  => true], 'objects', 'and');
			$taxonomies = array_keys($taxonomies);

			foreach($taxonomies as $taxonomy){
				$options['titles_tax_titles'][$taxonomy]['disabled'] = !empty($_POST['siteseo_options'][$taxonomy]['disabled']) ? true : false;
				$options['titles_tax_titles'][$taxonomy]['title'] = isset($_POST['siteseo_options'][$taxonomy]['title']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$taxonomy]['title'])) : '';
				$options['titles_tax_titles'][$taxonomy]['description'] = isset($_POST['siteseo_options'][$taxonomy]['desc']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options'][$taxonomy]['desc'])) : '';
				$options['titles_tax_titles'][$taxonomy]['noindex'] = isset($_POST['siteseo_options'][$taxonomy]['noindex']);
				$options['titles_tax_titles'][$taxonomy]['nofollow'] = isset($_POST['siteseo_options'][$taxonomy]['nofollow']);
			}
        }

        $options = apply_filters('siteseo_titles_save_settings', $options);

        update_option('siteseo_titles_option_name', $options);
    }
 }
settings/analytics.php000064400000166213151526415240011122 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Analytics{

	static function menu(){
		global $siteseo;

		$analytics_toggle = isset($siteseo->setting_enabled['toggle-google-analytics']) ? $siteseo->setting_enabled['toggle-google-analytics'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_google_analytics';

		$analytics_sub_tags = [
			'tab_google_analytics' => esc_html__('Google Analytics', 'siteseo'),
			'tab_matomo' => esc_html__('Matomo', 'siteseo'),
			'tab_clarity' => esc_html__('Clarity', 'siteseo'),
			'tab_advanced' => esc_html__('Advanced', 'siteseo'),
			'tab_cookie' => esc_html__('Cookie bar / GDPR', 'siteseo'),
			'tab_custom_tracking' => esc_html__('Custom Tracking', 'siteseo'),
		];
		
		echo '<div id="siteseo-root">';
		
		Util::admin_header();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';
		wp_nonce_field('siteseo_analytics_settings');

		Util::render_toggle('Analytics - SiteSEO', 'analytics_toggle', $analytics_toggle, $nonce);
        
		echo '<div id="siteseo-tabs" class="wrap">
			<div class="siteseo-nav-tab-wrapper">';

		foreach($analytics_sub_tags as $tab_key => $tab_caption){
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="'.esc_attr($tab_key).'-tab" class="siteseo-nav-tab'.esc_attr($active_class).'" data-tab="'.esc_attr($tab_key).'">'.esc_html($tab_caption).'</a>';
		}

		echo '</div>
		<div class="tab-content-wrapper">
		<div class="siteseo-tab'.($current_tab == 'tab_google_analytics' ? ' active' : '').'" id="tab_google_analytics" style="display: none;">';
		self::google_anlytics();
		echo '</div>     
		<div class="siteseo-tab'.($current_tab == 'tab_matomo' ? ' active' : '') . '" id="tab_matomo" style="display: none;">';
		self::matomo();
		echo '</div>     
		<div class="siteseo-tab'.($current_tab == 'tab_clarity' ? ' active' : '').'" id="tab_clarity" style="display: none;">';
		self::clarity();
		echo '</div>     
		<div class="siteseo-tab'.($current_tab == 'tab_advanced' ? ' active' : '').'" id="tab_advanced" style="display: none;">';
		self::advanced();
		echo '</div>     
		<div class="siteseo-tab'.($current_tab == 'tab_cookie' ? ' active' : '').'" id="tab_cookie" style="display: none;">';
		self::cookies();
		echo '</div>  
		<div class="siteseo-tab'.($current_tab == 'tab_custom_tracking' ? 'active' : '').'" id="tab_custom_tracking" style="display: none;">';
		self::custom_tracking();
		echo '</div>
		</div>';
		Util::submit_btn();
		echo '</form></div>';
	}
	
	static function custom_tracking(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}
		
		//$options = $siteseo->analaytics_settings;
		$options = get_option('siteseo_google_analytics_option_name');

		$option_head_tracking = !empty($options['google_analytics_other_tracking']) ? $options['google_analytics_other_tracking'] : '';
		$option_body_tracking = !empty($options['google_analytics_other_tracking_body']) ? $options['google_analytics_other_tracking_body'] : '';
		$option_footer_tracking = !empty($options['google_analytics_other_tracking_footer']) ? $options['google_analytics_other_tracking_footer'] : '';
		
		echo '<h3 class="siteseo-tabs">'.esc_html__('Custom Tracking','siteseo').'</h3>
			<P class="description">'.esc_html__('Add custom scripts like GTM or Facebook Pixel by copying and pasting the provided code into the HEAD, BODY, or FOOTER sections.','siteseo').'</p>
			<table class="form-table">
				<tbody>

					<tr>
						<th scope="row">'.esc_html__('[HEAD] Add an additional tracking code (like Facebook Pixel, Hotjar...)','siteseo').'</th>
						<td>
							<textarea name="siteseo_options[head_tracking]" rows="16" placeholder="'.esc_html__('Paste your tracking code here, such as Google Tag Manager (head). Do NOT paste GA4 or Universal Analytics codes, as they are automatically included in your source code.','siteseo').'">'.esc_html($option_head_tracking).'</textarea>
							<p class="description">'.esc_html__('This code will be added in the head section of your page','siteseo').'</p>
						</td>
					</tr>

					<tr>
						<th scope="row">'.esc_html__('[BODY] Add an additional tracking code (like Google Tag Manager...)','siteseo').'</th>
						<td>
							<textarea name="siteseo_options[body_tracking]" rows="16" placeholder="'.esc_html__('This code will be added just after the opening body tag of your page','siteseo').'">'.esc_html($option_body_tracking).'</textarea>
							<p>'.esc_html__('This code will be added just after the opening body tag of your page','siteseo').'</p>
							<p>'.esc_html__('You don‘t see your code? Make sure to call wp_body_open(); just after the opening body tag in your theme.','siteseo').'</p>
						</td>
					</tr>

					<tr>
						<th scope="row">'.esc_html__('[BODY (FOOTER)] Add an additional tracking code (like Google Tag Manager...)', 'siteseo').'</th>
						<td>
							<textarea name="siteseo_options[footer_tracking]" rows="16" placeholder="'.esc_html__('Paste your tracking code here(footer)','siteseo').'">'.esc_html($option_footer_tracking).'</textarea> 
							<p>'.esc_html__('This code will be added just after the closing body tag of your page','siteseo').'</P>
						</td>
					</tr>
				</tbody>
			</table><input type="hidden" name="siteseo_options[custom_tracking_tab]" value="1"/>';
		
	}

	static function cookies(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		//$options = $siteseo->analaytics_settings;
		$options = get_option('siteseo_google_analytics_option_name');

		$option_cookies_postion = !empty($options['google_analytics_hook']) ? $options['google_analytics_hook'] : '';
		$option_tracking_opt = !empty($options['google_analytics_disable']) ? $options['google_analytics_disable'] : '';
		$option_half_disable = !empty($options['google_analytics_half_disable']) ? $options['google_analytics_half_disable'] : '';
		$option_opt_choices = !empty($options['google_analytics_opt_out_edit_choice']) ? $options['google_analytics_opt_out_edit_choice'] : '';
		$option_opt_msg = !empty($options['google_analytics_opt_out_msg']) ? $options['google_analytics_opt_out_msg'] : '';
		$option_opt_msg_ok = !empty($options['google_analytics_opt_out_msg_ok']) ? $options['google_analytics_opt_out_msg_ok'] : '';
		$option_opt_msg_close = !empty($options['google_analytics_opt_out_msg_close']) ? $options['google_analytics_opt_out_msg_close'] : '';
		$option_opt_msg_edit = !empty($options['google_analytics_opt_out_msg_edit']) ? $options['google_analytics_opt_out_msg_edit'] : '';
		$option_cd_exp_date = !empty($options['google_analytics_cb_exp_date']) ? $options['google_analytics_cb_exp_date'] : '30';
		$option_cd_pos = !empty($options['google_analytics_cb_pos']) ? $options['google_analytics_cb_pos'] : '';
		$option_cd_txt_align = !empty($options['google_analytics_cb_txt_align']) ? $options['google_analytics_cb_txt_align'] : '';
		$option_cd_width = !empty($options['google_analytics_cb_width']) ? $options['google_analytics_cb_width'] : '';
		$option_cd_backdrop = !empty($options['google_analytics_cb_backdrop']) ? $options['google_analytics_cb_backdrop'] : '';
		$option_cd_scheme = !empty($options['google_analytics_cb_scheme']) ? $options['google_analytics_cb_scheme'] : '';

		//colors load
		$option_backdrop_bg = !empty($options['google_analytics_cb_backdrop_bg']) ? $options['google_analytics_cb_backdrop_bg'] : '';
		$option_cookiebar_bg = !empty($options['google_analytics_cb_bg']) ? $options['google_analytics_cb_bg'] : '#ffffff';
		$option_cookiebar_txt = !empty($options['google_analytics_cb_txt_col']) ? $options['google_analytics_cb_txt_col'] : '#000000';
		$option_cookiebar_lk = !empty($options['google_analytics_cb_lk_col']) ? $options['google_analytics_cb_lk_col'] : '#0000ff';
		$option_primarybtn_bg = !empty($options['google_analytics_cb_btn_bg']) ? $options['google_analytics_cb_btn_bg'] : '#0073aa';
		$option_primarybtn_bg_hov = !empty($options['google_analytics_cb_btn_bg_hov']) ? $options['google_analytics_cb_btn_bg_hov'] : '#005f8b';
		$option_primarybtn_txt = !empty($options['google_analytics_cb_btn_col']) ? $options['google_analytics_cb_btn_col'] : '#ffffff';
		$option_primarybtn_txt_hov = !empty($options['google_analytics_cb_btn_col_hov']) ? $options['google_analytics_cb_btn_col_hov'] : '#ffffff';
		$option_sec_bg = !empty($options['google_analytics_cb_btn_sec_bg']) ? $options['google_analytics_cb_btn_sec_bg'] : '#cccccc';
		$option_sec_bg_hov = !empty($options['google_analytics_cb_btn_sec_bg_hov']) ? $options['google_analytics_cb_btn_sec_bg_hov'] : '#aaaaaa';
		$option_sec_bg_txt = !empty($options['google_analytics_cb_btn_sec_col']) ? $options['google_analytics_cb_btn_sec_col'] : '#000000';
		$option_sec_bg_txt_hov = !empty($options['google_analytics_cb_btn_sec_col_hov']) ? $options['google_analytics_cb_btn_sec_col_hov'] : '#000000';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Cookies','siteseo').'</h3>
		<p class="description">'.esc_html__('Easily manage user consent for GDPR and customize your cookie bar.','siteseo').'</p>
		<p class="description">'.esc_html__('Compatible with Google Analytics and Matomo.','siteseo').'</p>
		<table>
			<tbody class="form-table">
				<tr>
					<div class="siteseo-notice" id="custom-dimensions">
						<span class="dashicons dashicons-info"></span>
						<p>'.
						/* translators: placeholders are just <strong> tag */ 
						wp_kses_post(sprintf(__('%1$s Note : %2$s This feature applies only to cookies added through SiteSEO analytics and tracking.', 'siteseo'), '<strong>', '</strong>')).'</p>
					</div>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Where to load the cookie bar?','siteseo').'</th>
					<td>
						<select name="siteseo_options[cookie_pos]">
							<option value="wp_body_open" '.selected($option_cookies_postion, 'wp_body_open', false).'>'.esc_html__('After the opening body tag (recommended)', 'siteseo').'</option>
							<option value="wp_footer" '.selected($option_cookies_postion, 'wp_footer', false).'>'.esc_html__('Footer', 'siteseo') .'</option>
							<option value="wp_head" '.selected($option_cookies_postion, 'wp_head', false).'>'.esc_html__('Header (not recommended)', 'siteseo').'</option>
						</select>
					</td>
				</tr>

				<tr>
					<th scope"user-select:auto">'.esc_html__('Analytics tracking opt-in','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[opt_tracking]" type="checkbox" '.(!empty($option_tracking_opt) ? 'checked="yes"' : 'value="1"').' />
								'.esc_html__('Obtain user consent for analytics tracking, as required by GDPR.', 'siteseo').'
                        </label><br/><br/>
						<label>
						<input type="checkbox" name="siteseo_options[half_disable]" '.(!empty($option_half_disable) ? 'checked="yes"' : 'value="1"').' />
							'.esc_html__('Display and automatically accept if user does not accept or reject within 10 seconds.','siteseo').'
						</label>
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto:">'.esc_html__('Allow user to change its choice','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[opt_edit_choices]" type="checkbox" '.(!empty($option_opt_choices) ? 'checked="yes"' : 'value="1"').' />
							Allow user to change its choice about cookies'.esc_html__('Request user consent for analytics tracking (required by GDPR)', 'siteseo').'
                        </label>
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Consent message for user tracking','siteseo').'</th>
					<td>
						<textarea placeholder="'.esc_html__('Enter your message (HTML allowed)','siteseo').'" name="siteseo_options[opt_msg]" >'.esc_attr($option_opt_msg).'</textarea>
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Accept button for user tracking','siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[opt_msg_ok]" value="'.esc_attr($option_opt_msg_ok).'" placeholder="'.esc_html__('Accept','siteseo').'"> 
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Close button','siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[opt_close]" value="'.esc_attr($option_opt_msg_close).'" placeholder="'.esc_attr__('default:X', 'siteseo').'">
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;" >'.esc_html__('Edit cookies button','siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[opt_edit_btn]" value="'.esc_attr($option_opt_msg_edit).'" placeholder="'.esc_attr__('default:Manage cookie', 'siteseo').'">
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('User consent cookie expiration date','siteseo').'</th>
					<td>
						<input type="number"  name="siteseo_options[cd_exp_date]" value="'.esc_attr($option_cd_exp_date).'" >
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Cookie bar position','siteseo').'</th>
					<td>
						<select name="siteseo_options[cd_pos]">
							<option value="bottom" '.selected($option_cd_pos, 'bottom', false).'>'.esc_html__('Bottom (default)','siteseo').'</option>
							<option value="middle" '.selected($option_cd_pos, 'middle', false).'>'.esc_html__('Middle','siteseo').'</option>
							<option value="top" '.selected($option_cd_pos, 'top', false).'>'.esc_html__('Top','siteseo').'</option>
						</select>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="use-select:auto;">'.esc_html__('Text alignment','siteseo').'</th>
					<td>
						<select name="siteseo_options[cd_txt_align]">
							<option value="center" '.selected($option_cd_txt_align, 'center', false).'>'.esc_html__('Center (default)', 'siteseo').'</option>
							<option value="left" '.selected($option_cd_txt_align, 'left', false).'>'.esc_html__('Left', 'siteseo').'</option>
							<option value="right" '.selected($option_cd_txt_align, 'right', false).'>'.esc_html__('Right', 'siteseo').'</option>
						</select>
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Cookie bar width', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[cd_width]"  value="'.esc_attr($option_cd_width).'"/>
						<p class="description">'.esc_html__('The default unit is Pixels. To use percentages, simply add % after your custom value (e.g., 80%).', 'siteseo').'</p>
						<br/>
						<span class="line"></span>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;"></th>
					<td>
						<h3>'.esc_html__('Backdrop', 'siteseo').'</h3>
						<p>'.esc_html__('Customize the backdrop of the cookie bar.', 'siteseo').'</p><br/>
						<label>
							<input type="checkbox" name="siteseo_options[cd_backdrop]" '.(!empty($option_cd_backdrop) ? 'checked="yes"' : 'value="1"').'>'. esc_html__('Display a backdrop with the cookie bar', 'siteseo') .'
						</label>
						<br/><br/>
						<p>'.esc_html__('Background color:','siteseo').'</p><br/>
						<input type="color" placeholder="Select color" name="siteseo_options[backdrop_bg]" value="'.esc_attr($option_backdrop_bg).'"/>
						<br/></br/>
						<span class="line"></span>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;"></th>
					<td>
						<h3>'.esc_html__('Main settings', 'siteseo').'</h3>
						<p>'.esc_html__('Customize the general settings of the cookie bar', 'siteseo').'</p>
						<p>'.esc_html__('Background color:', 'siteseo').'</p><br/>
						<input type="color"  placeholder="'.esc_html__('Select color', 'siteseo').'" name="siteseo_options[cookiesbar_bg]" value="'.esc_attr($option_cookiebar_bg).'"/>
						<p>'.esc_html__('Text color:', 'siteseo').'</p><br/>
						<input type="color"  placeholder="'.esc_html__('Select color', 'siteseo').'" name="siteseo_options[cookiebar_txt]" value="'.esc_attr($option_cookiebar_txt).'"/>
						<p>'.esc_html__('Link color: ','siteseo').'</p></br>
						<input type="color"  placeholder="'.esc_html__('Select color', 'siteseo').'" name="siteseo_options[line_co]" value="'.esc_attr($option_cookiebar_lk).'"/><br/></br>
						<span class="line"></span>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="use-select:auto"></th>
					<td>
						<h3>'.esc_html__('Primary button', 'siteseo').'</h3>
						<p>'.esc_html__('Customize the Accept button', 'siteseo').'</p><br/>
						<p>'.esc_html__('Background color:', 'siteseo').'</p>
						<input type="color"  placeholder="'.esc_html__('Select color', 'siteseo').'" name="siteseo_options[primary_btn_bg]" value="'.esc_attr($option_primarybtn_bg).'"/><br/><br/>
						<p>'.esc_html__('Background color on hover:','siteseo').'</p>
						<input type="color" name="siteseo_options[primary_btn_bg_hov]" value="'.esc_attr($option_primarybtn_bg_hov).'" /><br/><br/>
						<p>'.esc_html__('Text color:', 'siteseo').'</p>
						<input type="color" name="siteseo_options[primary_btn_txt]" value="'.esc_attr($option_primarybtn_txt).'"/>
						<p>'. esc_html__('Text color on hover:', 'siteseo') .'</p>
						<input type="color" name="siteseo_options[primary_btn_txt_hov]" value="'.esc_attr($option_primarybtn_txt_hov).'"/><br/><br/>
						<span class="line"></span>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto"></th>
					<td>
						<h3>'.esc_html__('Secondary button', 'siteseo').'</h3>
						<p>'.esc_html__('Customize the Accept button', 'siteseo').'</p><br/>
						<p>'.esc_html__('Background color:', 'siteseo').'</p>
						<input type="color"  placeholder="'.esc_html__('Select color','siteseo').'" name="siteseo_options[sec_btn_bg]" value="'.esc_attr($option_sec_bg).'"/><br/><br/>
						<p>'.esc_html__('Background color on hover:', 'siteseo').'</p>
						<input type="color" name="siteseo_options[sec_btn_bg_hov]" value="'.esc_attr($option_sec_bg_hov).'"/><br/><br/>
						<p>'.esc_html__('Text color:', 'siteseo').'</p>
						<input type="color" name="siteseo_options[sec_btn_txt]" value="'.esc_attr($option_sec_bg_txt).'"/>
						<p>'.esc_html__('Text color on hover:', 'siteseo').'</p>
						<input type="color" name="siteseo_options[sec_btn_txt_hov]" value="'.esc_attr($option_sec_bg_txt_hov).'"/>
					</td>
				</tr>
			</tbody>
		</table><input type="hidden" name="siteseo_options[cookies_tab]" value="1"/>'; 

	}
	

	static function matomo(){
		global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		//$options = $siteseo->analaytics_settings;
		$options = get_option('siteseo_google_analytics_option_name');

		$option_enable_matomo = !empty($options['google_analytics_matomo_enable']) ? $options['google_analytics_matomo_enable'] : '';
		$option_self_hosted = !empty($options['google_analytics_matomo_self_hosted']) ? $options['google_analytics_matomo_self_hosted'] : '';
		$option_matomo_id = !empty($options['google_analytics_matomo_id']) ? $options['google_analytics_matomo_id'] : '';
		$option_site_id = !empty($options['google_analytics_matomo_site_id']) ? $options['google_analytics_matomo_site_id'] : '';
		$option_sub_domain = !empty($options['google_analytics_matomo_subdomains']) ? $options['google_analytics_matomo_subdomains'] : '';
		$option_site_domain = !empty($options['google_analytics_matomo_site_domain']) ? $options['google_analytics_matomo_site_domain'] : '';
		$option_enable_corss_domain = !empty($options['google_analytics_matomo_cross_domain']) ? $options['google_analytics_matomo_cross_domain'] : '';
		$option_no_js = !empty($options['google_analytics_matomo_no_js']) ? $options['google_analytics_matomo_no_js'] : '';
		$option_cross_domain_sites = !empty($options['google_analytics_matomo_cross_domain_sites']) ? $options['google_analytics_matomo_cross_domain_sites'] : '';
		$option_no_cookies = !empty($options['google_analytics_matomo_no_cookies']) ? $options['google_analytics_matomo_no_cookies'] : '';
		$options_link_tracking = !empty($options['google_analytics_matomo_link_tracking']) ? $options['google_analytics_matomo_link_tracking'] : '';
		$options_no_heatmaps = !empty($options['google_analytics_matomo_no_heatmaps']) ? $options['google_analytics_matomo_no_heatmaps'] : '';
		$options_matomo_dtn = !empty($options['google_analytics_matomo_dnt']) ? $options['google_analytics_matomo_dnt'] : '';

		$matomo_subtabs = [
			'tracking' => 'Tracking',
		];

		echo '<table class="form-table">
			<tbody>
				<tr>
					<th scope="row">
						<div class="siteseo-container">';
								$is_first = true;
								foreach($matomo_subtabs as $post_key => $post_val){
									$active_class = $is_first ? 'active' : '';
									echo '<a href="#'.esc_attr($post_key).'" class="'.esc_attr($active_class).'">'.esc_html($post_val).'</a>';
									$is_first = false;
								}
							echo '</div>
					</th>
					<td>
						<h3>'.esc_html__('Matomo', 'siteseo').'</h3>
						<div class="siteseo_wrap_label" id="tracking">
						<p class="description">'.esc_html__('Track your users with privacy in mind using Matomo. We support both On-Premise and Cloud installations.', 'siteseo').'</p>
						</div>
						<span class="line"></span>
						<h3>'.esc_html__('Tracking', 'siteseo').'</h3>
						<table class="form-table">
							<tbody>
								<tr>
									<th scope="row">'.esc_html__('Enable Matomo tracking.', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[enable_matomo]" '.(!empty($option_enable_matomo) ? 'checked="yes"' : '').' value="1"/>
											'.esc_html__('Enable Matomo tracking', 'siteseo') .'
										</label>
										<p class="description">'.esc_html__('A Matomo Cloud account or a self-hosted Matomo installation is necessary.', 'siteseo').'</p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Self hosted Matomo installation.', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[self_hosted]" '.(!empty($option_self_hosted) ? 'checked="yes"' : '').' value="1" "/>
											'.esc_html__('Yes, self-hosted installation', 'siteseo').'
										</label>
										
									</td>
								</tr>
								
								<tr>
									<th scope="row">'.esc_html__('Enter your tracking ID', 'siteseo').'</th>
									<td>
										<input type="text" placeholder="'.esc_html__('Enter "example" if you Matomo account URL is "example.matomo.cloud', 'siteseo').'" name="siteseo_options[tracking_id]" value="'.esc_attr($option_matomo_id).'"/>
										'.wp_kses_post('<p class="description">Enter only the host without quotes, such as "example.matomo.cloud" </br> (Cloud) or "matomo.example.com" (self-hosted).</p>').'
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enter your site ID.', 'siteseo').'</th>
									<td>
										<input type="text" placeholder="'.esc_html__('Enter your site ID', 'siteseo').'" name="siteseo_options[site_id]" value="'.esc_attr($option_site_id).'"/>
										<p class="description">'.
										/* translators: placeholders are just <strong> tag */ 
										wp_kses_post(sprintf(__('To find your site ID, visit your %1$s Matomo Cloud %2$s account, go to Websites, and click Manage. The <br/>"Site ID" will be displayed on the right side.', 'siteseo'), '<strong>', '</strong>')).'</p>
										<p class="description">'.
										/* translators: placeholder is just <br> tag */ 
										wp_kses_post(sprintf(__('For self-hosted installations, navigate to your Matomo administration, then go to Settings, Websites, %1$s and Manage. From the list of websites, locate the "ID" line.', 'siteseo'), '<br/>')).'<p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Track visitors across all subdomains', 'siteseo').'</th>
									<td>
										<label>
										<input type="checkbox" name="siteseo_options[track_visitors]" '.(!empty($option_sub_domain) ? 'checked="yes"' : '').' value="1"/>
										'.esc_html__('Monitor one domain along with its subdomains on the same website.','siteseo') .'
										<p class=description">'.esc_html__('If a visitor visits x.example.com and y.example.com, they will be counted as a single unique visitor.', 'siteseo').'</p>
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Prepend the site domain.', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[site_domain]" '.(!empty($option_site_domain) ? 'checked="yes"' : '').' value="1" />
											'.esc_html__('Add the site domain before the page title when tracking', 'siteseo').'
											<p class="description">For example, if someone visits the About page on blog.example.com, it will be recorded as "blog / About".<br/> This provides a simple way to get an overview of your traffic by subdomain.</p>`
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Track users with JavaScript disabled.', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[track_users]" '.(!empty($option_no_js) ? 'checked="yes"' : '').' value="1" />
											'. esc_html__('Track users with JavaScript disabled', 'siteseo').'
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enables cross domain linking', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[enable_cross_domains]" '.(!empty($option_enable_corss_domain) ? 'checked="yes"' : '').' value="1" />
											'.esc_html__('Enables cross domain linking', 'siteseo').'
										</label>
										<p class="description">'.esc_html__('By default, the visitor ID, which uniquely identifies each visitor, is stored in the browser first-party cookies. These cookies can only be accessed by pages on the same domain.', 'siteseo').'</p> 
										<p class="description">'.esc_html__('Enabling cross-domain tracking allows you to monitor all actions and pageviews of a specific visitor within the same session, even when they visit pages across different domains.', 'siteseo').'</p> 
										<p class="description">'.esc_html__('When a user clicks on a link to one of your site alias URLs, a URL parameter, <code>pk_vid</code>, will be appended, forwarding the Visitor ID.', 'siteseo').'</p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Cross domain', 'siteseo').'</th>
									<td>
										<input type="text" name="siteseo_options[corss_domains]" value="'.esc_attr($option_cross_domain_sites).'" placeholder="'.esc_attr('Enter your domains: siteseo.io,sub.siteseo.io,sub2.siteseo.io').'"/>
									</td>
								</tr>
								
								<tr>
									<th scope="row">'.esc_html__('Enable DoNotTrack detection', 'siteseo').'</th>
									<td>
										<input type="checkbox" name="siteseo_options[enable_donottack]" '.(!empty($options_matomo_dtn) ? 'checked="yes"' : '').' value="1"/>
										'.esc_html__('Activate client-side Do Not Track detection.', 'siteseo').'
										<p class="description">'.esc_html__('Tracking requests will be blocked if visitors opt out of being tracked.', 'siteseo').'</p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Disable all tracking cookies.', 'siteseo').'</th>
									<td>
										<input type="checkbox" name="siteseo_options[disabled_cookies]" '.(!empty($option_no_cookies) ? 'checked="yes"' : '').' value="1" />
										'.esc_html__('Disables all first-party cookies. Any existing Matomo cookies for this site will be deleted on the next page view.', 'siteseo').'
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Download & Outlink tracking.', 'siteseo').'</th>	
									<td>
										<input type="checkbox" name="siteseo_options[outlink_tracking]" '.(!empty($options_link_tracking) ? 'checked="yes"' : '').' value="1" />
										'.esc_html__('Enabling Download & Outlink tracking','siteseo').'
										<p class="description">By default, files with any of these extensions will be treated as a "download" in the Matomo interface.<p>
										<div class="siteseo-styles pre"><pre>7z|aac|arc|arj|apk|asf|asx|avi|bin|bz|bz2|csv|deb|dmg|doc|exe|flv|gif|gz|gzip|hqx|jar|jpg|jpeg|js|mp2|mp3|mp4|mpg|mpeg|mov|movie|msi|msp|odb|odf|odg|odp|ods|odt|ogg|ogv| pdf|phps|png|ppt|qt|qtm|ra|ram|rar|rpm|sea|sit|tar|tbz|tbz2|tgz|torrent|txt|wav|wma|wmv|wpd|xls|xml|z|zip</pre></div>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Disable all heatmaps and session recordings.', 'siteseo').'</th>
									<td>
										<input type="checkbox" '.(!empty($options_no_heatmaps) ? 'checked="yes"' : '').' value="1" name="siteseo_options[disabled_heatmaps]" />
										'.esc_html__('Turns off all heatmaps and session recordings.', 'siteseo').'
									</td>
								</tr>
							</tbody>
						</table>
					</td>
				</tr>
			</tbody>
		</table><input type="hidden" name="siteseo_options[matomo_tab]" value="1"/>';
	}

	static function advanced(){
		global $siteseo,$wp_roles;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		if(!isset($wp_roles)){
			$wp_roles = new \WP_Roles();
		}

		//$options = $siteseo->analaytics_settings;
		$options = get_option('siteseo_google_analytics_option_name');

		$option_track_authors = !empty($options['google_analytics_cd_author']) ? $options['google_analytics_cd_author'] : '';
		$option_track_categories = !empty($options['google_analytics_cd_category']) ? $options['google_analytics_cd_category'] : '';
		$option_track_tag = !empty($options['google_analytics_cd_tag']) ? $options['google_analytics_cd_tag'] : '';
		$option_track_post_types = !empty($options['google_analytics_cd_post_type']) ? $options['google_analytics_cd_post_type'] : '';
		$option_logged_user = !empty($options['google_analytics_cd_logged_in_user']) ? $options['google_analytics_cd_logged_in_user'] : '';

		$adavnced_subtabs =[
			'custom-dimensions' => 'Custom Dimensions',
			'Misc' => 'Misc',
		];

		echo '<table class="form-table">
				<tbody>
					<tr>
						<th scope="row">
							<div class="siteseo-container">';
								$is_first = true;
								foreach($adavnced_subtabs as $post_key => $post_val){
									$active_class = $is_first ? 'active' : '';
									echo '<a href="#'.esc_attr($post_key).'" class="'.esc_attr($active_class).'">'.esc_html($post_val).'</a>';
									$is_first = false;
								}
							echo '</div>
						</th>

						<td>
							<h3>'.esc_html__('Advanced settings', 'siteseo').'</h3>
							<div class="siteseo-notice" id="custom-dimensions">
								<span class="dashicons dashicons-info"></span>
								<p>'.esc_html__('All advanced settings are compatible with both Google Analytics and Matomo tracking codes.', 'siteseo').'</p>
							</div>

							<br/>

							<span class="line"></span>
							<h3>'.esc_html__('Custom Dimensions', 'siteseo').'</h3>
							<div class="siteseo_wrap_label"><p class="description">'.esc_html__('Set up your Google Analytics custom dimensions.', 'siteseo').'</p></div>
							<div class="siteseo_wrap_label"><p class="description">'.esc_html__('Custom dimensions and metrics are similar to the default ones in Google Analytics, but you have the flexibility to create your own.', 'siteseo').'</p></div>
							<div class="description"><p class="description">'.esc_html__('Utilize custom dimensions to gather and analyze data that Google Analytics does not track automatically.', 'siteseo').'</p></div>
							<div class="description"><p class="description">'.esc_html__('Remember, you must also configure your custom dimensions in your Google Analytics account. Click the help icon for more information.', 'siteseo').'</p></div>

							<table class="form-table">
								<tbody>
									<tr>
										<th scope="row">'.esc_html__('Track Authors', 'siteseo').'</th>
										<td>
											<select name="siteseo_options[track_authors]">
												<option value="none" '.selected($option_track_authors, 'none', false).'>'.esc_html__('None','siteseo').'</option>';
												for($i = 1; $i <= 20; ++$i){
													/* translators: %d represents the custom dimension */
													echo '<option '.selected($option_track_authors, 'dimension' . $i, false).' value="dimension'.esc_attr($i).'">'.sprintf(esc_html__('Custom Dimension #%d', 'siteseo'), esc_html($i)).'</option>';
												}
											echo '</select>
										</td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Track Categories', 'siteseo').'</th>
										<td>
											<select name="siteseo_options[track_categories]">
												<option value="none" '.selected($option_track_categories, 'none', false).'>'.esc_html__('None','siteseo').'</option>';
												for($i = 1; $i <= 20; ++$i){
													/* translators: %d represents the custom dimension */
													echo '<option '.selected($option_track_categories, 'dimension' . $i, false).' value="dimension'.esc_attr($i).'">'.sprintf(esc_html__('Custom Dimension #%d', 'siteseo'), esc_html($i)).'</option>';
												}
											echo '</select>
										</td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Track Tags', 'siteseo').'</th>
										<td>
											<select name="siteseo_options[track_tags]">
												<option value="none" '.selected($option_track_tag, 'none', false).'>'.esc_html__('None','siteseo').'</option>';
												for($i = 1; $i <= 20; ++$i){
													/* translators: %d represents the custom dimension */
													echo '<option '.selected($option_track_tag, 'dimension' . $i, false).' value="dimension'.esc_attr($i).'">'.sprintf(esc_html__('Custom Dimension #%d', 'siteseo'), esc_html($i)).'</option>';
												}
											echo '</select>
										</td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Track Post Types','siteseo').'</th>
										<td>
											<select name="siteseo_options[track_post_types]">
												<option value="none" '.selected($option_track_post_types, 'none', false).'>'.esc_html__('None','siteseo').'</option>';
												for($i = 1; $i <= 20; ++$i){
													/* translators: %d represents the custom dimension */
													echo '<option '.selected($option_track_post_types, 'dimension' . $i, false).' value="dimension'.esc_attr($i).'">'.sprintf(esc_html__('Custom Dimension #%d', 'siteseo'), esc_html($i)).'</option>';
												}
											echo '</select>
										</td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Track Logged In Users','siteseo').'</th>
										<td>
											<select name="siteseo_options[track_user]">
												<option value="none" '.selected($option_logged_user, 'none', false).'>'.esc_html__('None','siteseo').'</option>';
												for($i = 1; $i <= 20; ++$i){
													/* translators: %d represents the custom dimension */
													echo '<option '.selected($option_logged_user, 'dimension' . $i, false).' value="dimension'.esc_attr($i).'">'. sprintf(esc_html__('Custom Dimension #%d', 'siteseo'), esc_html($i)).'</option>';
												}
											echo '</select>
										</td>
									</tr>

								</tbody>
							</table>

							<div class="description" id="Misc"><span class="line"></span>
							<h3>'.esc_html__('Misc','siteseo').'</h3>
							<table>
								<tbody class="form-table">
									<tr>
										<th scope="row">'.esc_html__('Exclude user roles from tracking (Google Analytics and Matomo)','siteseo').'</th>
										<td>';
										foreach($wp_roles->get_names() as $key => $value){
											$select = isset($options['google_analytics_roles'][$key]);

											echo '<p>
												<label>
													<input name="siteseo_options[misc_roles]['.esc_attr($key).']" type="checkbox" '.(!empty($select) ? 'checked="yes"' : 'value="1"').'/>
													<strong>'. esc_html($value) .'</strong> (<em> '. esc_html(translate_user_role($value,  'default')) .'</em>)
												</label>
											</p>';	
										}
										echo '</td>
									</tr>
								</tbody>
							</table>
							</div>
						</td>
					</tr>
				</tbody>
			</table><input type="hidden" name="siteseo_options[advanced_tab]" value="1"/>';
	}
	
	static function clarity(){
		global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		//$options = $siteseo->analaytics_settings;
		$options = get_option('siteseo_google_analytics_option_name');

		$option_enable_clarity = !empty($options['google_analytics_clarity_enable']) ? $options['google_analytics_clarity_enable'] : '';
		$option_project_id = !empty($options['google_analytics_clarity_project_id']) ? $options['google_analytics_clarity_project_id'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Microsoft Clarity', 'siteseo').'</h3>
		<p class="description">'.esc_html__('Use Microsoft Clarity to capture session recordings, access instant heatmaps, and gain powerful insights for free. Understand how users interact with your site to enhance the user experience and boost conversions.', 'siteseo').'</p>

		<div class="siteseo-notice">
            		<span class="dashicons dashicons-info"></span>
           		 <p>'. 
				 /* translators: %s represents the microsoft clarity api url */
				 wp_kses_post(sprintf(__('Create your first Microsoft Clarity project %1$shere%2$s.', 'siteseo'), '<a href="https://clarity.microsoft.com/" target="_blank">', '</a>')) .'</p>
		</div>

		<table class="form-table">
			<tbody>
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Enable Microsoft Clarity','siteseo').'</th>
					<td>
						<input type="checkbox" name="siteseo_options[microsoft_clarity]" '.(!empty($option_enable_clarity) ? 'checked="yes"' : ''). ' value="1">
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Enter your Clarity project ID', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[project_id]" placeholder="'.esc_attr__('Enter your Project Id', 'siteseo').'" value="'.esc_attr($option_project_id).'" >
						<p><span class="dashicons dashicons-external"></span>
							<a href="https://siteseo.io/docs/analytics/find-my-microsoft-clarity-project-id/" target="_blank">
								'.esc_html__('Find your project ID', 'siteseo').'
							</a>
							</span>
						</p>
					</td>
				</tr>

			</tbody>
		</table><input type="hidden" name="siteseo_options[clarity_tab]" value="1" />';

	}

	static function google_anlytics(){
		global $siteseo;
		
        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		$options = get_option('siteseo_google_analytics_option_name');
		//$options = $siteseo->analaytics_settings;

		$option_enable_anaytics = !empty($options['google_analytics_enable']) ? $options['google_analytics_enable'] : '';
		$option_anaytics_id = !empty($options['google_analytics_ga4']) ? $options['google_analytics_ga4'] : '';
		$option_enable_optimize = !empty($options['google_analytics_link_tracking_enable']) ? $options['google_analytics_link_tracking_enable'] : '';
		$option_enable_download_tracking= !empty($options['google_analytics_download_tracking_enable']) ? $options['google_analytics_download_tracking_enable'] : '';
 		$option_download_tracking = !empty($options['google_analytics_download_tracking']) ? $options['google_analytics_download_tracking'] : '';
		$option_affiliate_tracking_enable = !empty($options['google_analytics_affiliate_tracking_enable']) ? $options['google_analytics_affiliate_tracking_enable'] : '';
		$option_affiliate_tracking = !empty($options['google_analytics_affiliate_tracking']) ? $options['google_analytics_affiliate_tracking'] : '';
		$option_phone_tracking = !empty($options['google_analytics_phone_tracking']) ? $options['google_analytics_phone_tracking'] : '';

		$option_container_id = !empty($options['google_analytics_optimize']) ? $options['google_analytics_optimize'] : '';
		$option_conversion_id = !empty($options['google_analytics_ads']) ? $options['google_analytics_ads'] : '';
		$option_ip_anonymization = !empty($options['google_analytics_ip_anonymization']) ? $options['google_analytics_ip_anonymization'] : '';
		$option_links_attribution = !empty($options['google_analytics_link_attribution']) ? $options['google_analytics_link_attribution'] : '';
		$option_domain_tracking = !empty($options['google_analytics_cross_enable']) ? $options['google_analytics_cross_enable'] : '';
		$option_cross_domain = !empty($options['google_analytics_cross_domain']) ? $options['google_analytics_cross_domain'] : '';
		$option_enable_remarketing = !empty($options['google_analytics_remarketing']) ? $options['google_analytics_remarketing'] : '';
 		
		$google_analytics_fileds = [
			'general-settings' =>'General',
			'tracking-settings'=>'Tracking',
			'events-settings' => 'Events'
		];

		echo '<table class="form-table">
			<tbody>
				<tr>
					<th scope="row">
					<div class="siteseo-container">';
						$is_first = true;
						foreach($google_analytics_fileds as $post_key => $post_val){
							$active_class = $is_first ? 'active' : '';
							echo '<a href="#'.esc_attr($post_key).'" class="'.esc_attr($active_class).'">'.esc_html($post_val).'</a>';
							$is_first = false;
						}
				echo '</div></th>
				<td>
					<div id="general-settings">
						<h3>'.esc_html__('Google Anlytics', 'siteseo').'</h3>
						<div class="siteseo_wrap_label"><p class="description">'.esc_html__('Connect your Google Analytics to your website. The tracking code will be automatically added to your site.', 'siteseo') .'</p></div>
						<span class="line"></span>
						<div class="siteseo_wrap_label"><p class="'.esc_html__('description">Link your Google Analytics to your website. The tracking code will be automatically added to your site', 'siteseo').'</p></div>
						<span class="line"></span>
						<table class="form-table">
								<tbody>
									<tr>
										<th scope="row">'.esc_html__('General', 'siteseo').'</th>
										<td></td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Enable Google Analytics tracking', 'siteseo').'</th>
										<td>
											<label><input type="checkbox" name="siteseo_options[google_anlytics_tracking]" '.(!empty($option_enable_anaytics) ? 'checked="yes"' : '') . ' value="1"/> ' . esc_html__('Activate Google Analytics tracking using the Global Site Tag (gtag.js).', 'siteseo') . '</label>
										</td>
									</tr>

									<tr>
										<th scope="row">'.esc_html__('Enter your measurement ID (GA4)', 'siteseo').'</th>
										<td>
											<input type="text" placeholder="'.esc_attr__('Enter your measurement ID (G-XXXXXXXXXX)','siteseo').'" name="siteseo_options[anlytics_measurement_id]" value="'.esc_attr($option_anaytics_id).'">
											<p>
												<span class="dashicons dashicons-external"></span>
												<a href="https://support.google.com/analytics/answer/9539598?hl=en&ref_topic=9303319" target="_blank">'.esc_html__('Find your measurement ID', 'siteseo').'</a>
											</p>
										</td>
									</tr>
								</tbody>
						</table>
					</div></div>
					
					<div id="tracking-settings">
						<span class="line"></span>
						<h3>'.esc_html__('Tracking','siteseo').'</h3>
						<p class="description">'.esc_html__('Set up your Google Analytics tracking code.', 'siteseo').'</P>
						<table class="form-table">
							<tbody>
								<tr>
									<th scope="row">'.esc_html__('Enable Google Optimize.', 'siteseo').'</th>
									<td>
										<label>
											<input type="text" name="siteseo_options[container_id]" placeholder="'.esc_attr__('Enter your Google Optimize container ID.', 'siteseo').'" value="'.esc_attr($option_container_id).'"/>
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enable Google Ads','siteseo').'</th>	
									<td>
										<label>
											<input type="text" placeholder="'.esc_attr__('Enter your Google Ads conversion ID (eg: AW-123456789).', 'siteseo').'" name="siteseo_options[conversion_id]" value="'.esc_attr($option_conversion_id).'"/>
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enable remarketing, demographics, and interests reporting', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[enable_remarketing]" '.(!empty($option_enable_remarketing) ? 'checked="yes"' : '').' value="1"/>
											'. esc_html__('Enable remarketing, demographics, and interests reporting', 'siteseo').'
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enable IP Anonymization', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[ip_anonymiza]" '.(!empty($option_ip_anonymization) ? 'checked="yes"' : '').'/>
											'. esc_html__('Enable IP Anonymization', 'siteseo') .'
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enhanced Link Attribution', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[link_attribution]" '.(!empty($option_links_attribution) ? 'checked="yes"' : '').'/>
											'. esc_html__('Enhanced Link Attribution', 'siteseo').'
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enable cross-domain tracking', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[domain_tracking]" '.(!empty($option_domain_tracking) ? 'checked="yes"' : '').' />
											'. esc_html__('Enable cross-domain tracking', 'siteseo').'
										</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Cross domains', 'siteseo').'</th>
									<td>
										<input type="text" placeholder="Enter your domains: siteseo.io,sub.siteseo.io,sub2.siteseo.io" name="siteseo_options[cross_domain]" value="'.esc_attr($option_cross_domain).'" />
									</td>
								</tr>

							</tbody>
						<table>
					</div>
					
					<div id="events-settings">
						<span class="line"></span>
						<h3>'.esc_html__('Events', 'siteseo').'</h3>
						<P class="description">'.esc_html__('Track events in Google Analytics', 'siteseo').'</p>
						<table class="form-table">
							<tbody>
								<tr>
									<th scope="row">'.esc_html__('Enable Google Optimize', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[google_optimize]" '.(!empty($option_enable_optimize) ? 'checked="yes"' : ''). ' value="1">' . esc_html__(' Enable external links tracking', 'siteseo') . '
										</label>
									</td>
								</tr>
								
								<tr>
									<th scope="row">'.esc_html__('Enable downloads tracking (eg: PDF, XLSX, DOCX...)', 'siteseo').'</th>
									<td>
										<label>
											<input type="checkbox" name="siteseo_options[enable_download_tracking]" '.(!empty($option_enable_download_tracking) ? 'checked="yes"' : '').' value="1"> '.esc_html__('Enable download tracking', 'siteseo').'
										</label>
									</td>
								</tr>
								
								<tr>
									<th scope="row">'.esc_html__('Track downloads clicks', 'siteseo').'</th>
									<td>
										<input type="text" placeholder="pdf|docs|pptx|zip" name="siteseo_options[track_downlaods]" value="'.esc_attr($option_download_tracking).'"/>
										<p class="description">'.esc_html__('Separate each file type extensions with a pipe "|"','siteseo').'</p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Enable affiliate/outbound links tracking (eg: aff, go, out, recommends)', 'siteseo').'</th>
									<td>
										<label>
										<input type="checkbox" name="siteseo_options[aff_tracking_enable]" '.(!empty($option_affiliate_tracking_enable ) ? 'checked="yes"' : '').' value="1"/>
										'. esc_html__('Enable affiliate/outbound tracking','siteseo') .'</label>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Track affiliate/outbound links','siteseo').'</th>
									<td>
										<input type="text" name="siteseo_options[aff_tracking]" placeholder="aff|go|out" value="'.esc_attr($option_affiliate_tracking).'"/>
										<p class="description">'.esc_html__('Separate each keyword with a pipe "|"', 'siteseo').'</p>
									</td>
								</tr>

								<tr>
									<th scope="row">'.esc_html__('Track phone links','siteseo').'</th>
									<td>
										<input type="checkbox" name="siteseo_options[track_phones]" '.(!empty($option_phone_tracking ) ? 'checked="yes"' : '') . ' value="1"/>
										'.esc_html__(' Enable tracking of "tel:" links' , 'siteseo'). '
										<div class="siteseo-styles pre"><pre>'.esc_html('<a href="tel:+33123456789">').'</pre></div>
									</td>
								</tr>
							</tbody>
						</table
					</div>
				</td>
			</tbody>
		</table>
		<input type="hidden" name="siteseo_options[analytics_tab]" value="1"/>';

	}

	static function save_settings(){

		global $siteseo;

		check_admin_referer('siteseo_analytics_settings');

		if(!siteseo_user_can('manage_analytics') || !is_admin()){
			return;
		}

		$options = [];
		
		if(empty($_POST['siteseo_options'])){
			return;
		}
		
		if(isset($_POST['siteseo_options']['analytics_tab'])){
			$options['google_analytics_enable'] = isset($_POST['siteseo_options']['google_anlytics_tracking']);
			$options['google_analytics_ga4'] = isset($_POST['siteseo_options']['anlytics_measurement_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['anlytics_measurement_id'])) : '';
			$options['google_analytics_link_tracking_enable'] = isset($_POST['siteseo_options']['google_optimize']);
			$options['google_analytics_download_tracking_enable'] = isset($_POST['siteseo_options']['enable_download_tracking']);
			$options['google_analytics_download_tracking'] = isset($_POST['siteseo_options']['track_downlaods']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_downlaods'])) : '';
			$options['google_analytics_affiliate_tracking_enable'] = isset($_POST['siteseo_options']['aff_tracking_enable']);
			$options['google_analytics_affiliate_tracking'] = isset($_POST['siteseo_options']['aff_tracking']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['aff_tracking'])) : '';
			$options['google_analytics_phone_tracking'] = isset($_POST['siteseo_options']['track_phones']);
			$options['google_analytics_optimize'] = isset($_POST['siteseo_options']['container_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['container_id'])) : '';
			$options['google_analytics_ads'] = isset($_POST['siteseo_options']['conversion_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['conversion_id'])) : '';
			$options['google_analytics_remarketing'] = isset($_POST['siteseo_options']['enable_remarketing']);
			$options['google_analytics_ip_anonymization'] = isset($_POST['siteseo_options']['ip_anonymiza']);
			$options['google_analytics_link_attribution'] = isset($_POST['siteseo_options']['link_attribution']);
			$options['google_analytics_cross_enable'] = isset($_POST['siteseo_options']['domain_tracking']);
			$options['google_analytics_cross_domain'] = isset($_POST['siteseo_options']['cross_domain']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cross_domain'])) : '';
		}
		
		if(isset($_POST['siteseo_options']['clarity_tab'])){
			$options['google_analytics_clarity_enable'] = isset($_POST['siteseo_options']['microsoft_clarity']);
			$options['google_analytics_clarity_project_id'] = isset($_POST['siteseo_options']['project_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['project_id'])) : '';
		}
		
		if(isset($_POST['siteseo_options']['matomo_tab'])){
			$options['google_analytics_matomo_enable'] = isset($_POST['siteseo_options']['enable_matomo']);
			$options['google_analytics_matomo_self_hosted'] = isset($_POST['siteseo_options']['self_hosted']);
			$options['google_analytics_matomo_id'] = isset($_POST['siteseo_options']['tracking_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['tracking_id'])) : '';
			$options['google_analytics_matomo_site_id'] = isset($_POST['siteseo_options']['site_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['site_id'])) : '';
			$options['google_analytics_matomo_subdomains'] = isset($_POST['siteseo_options']['track_visitors']);
			$options['google_analytics_matomo_site_domain'] = isset($_POST['siteseo_options']['site_domain']);
			$options['google_analytics_matomo_cross_domain'] = isset($_POST['siteseo_options']['enable_cross_domains']);
			$options['google_analytics_matomo_no_js'] = isset($_POST['siteseo_options']['track_users']);
			$options['google_analytics_matomo_cross_domain_sites'] = isset($_POST['siteseo_options']['corss_domains']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['corss_domains'])) : '';
			$options['google_analytics_matomo_no_cookies'] = isset($_POST['siteseo_options']['disabled_cookies']);
			$options['google_analytics_matomo_link_tracking'] = isset($_POST['siteseo_options']['outlink_tracking']);
			$options['google_analytics_matomo_no_heatmaps'] = isset($_POST['siteseo_options']['disabled_heatmaps']);
			$options['google_analytics_matomo_dnt'] = isset($_POST['siteseo_options']['enable_donottack']);
		}
		
		if(isset($_POST['siteseo_options']['advanced_tab'])){
		
			$options['google_analytics_cd_author'] = isset($_POST['siteseo_options']['track_authors']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_authors'])) : '';
			$options['google_analytics_cd_category'] = isset($_POST['siteseo_options']['track_categories']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_categories'])) : '';
			$options['google_analytics_cd_tag'] = isset($_POST['siteseo_options']['track_tags']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_tags'])) : '';
			$options['google_analytics_cd_post_type'] = isset($_POST['siteseo_options']['track_post_types']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_post_types'])) : '';
			$options['google_analytics_cd_logged_in_user'] = isset($_POST['siteseo_options']['track_user']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['track_user'])) : '';
			
			// mics roles
			if(isset($_POST['siteseo_options']['misc_roles'])){
				$options['google_analytics_roles'] = map_deep(wp_unslash($_POST['siteseo_options']['misc_roles']), 'sanitize_text_field');
			}
		}
		
		if(isset($_POST['siteseo_options']['custom_tracking_tab']) && current_user_can('unfiltered_html')){
			// NOTE: These options can not be sanitized as we need user to be able to add some JS code, so we have added a capability check which only a super admin can have.
			$options['google_analytics_other_tracking'] = isset($_POST['siteseo_options']['head_tracking']) ? wp_unslash($_POST['siteseo_options']['head_tracking']) : '';
			$options['google_analytics_other_tracking_body'] = isset($_POST['siteseo_options']['body_tracking']) ? wp_unslash($_POST['siteseo_options']['body_tracking']) : '';
			$options['google_analytics_other_tracking_footer'] = isset($_POST['siteseo_options']['footer_tracking']) ? wp_unslash($_POST['siteseo_options']['footer_tracking']) : '';
		}
		
		if(isset($_POST['siteseo_options']['cookies_tab'])){
			
			$options['google_analytics_hook'] = isset($_POST['siteseo_options']['cookie_pos']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cookie_pos'])) : '';
			$options['google_analytics_disable'] = isset($_POST['siteseo_options']['opt_tracking']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['opt_tracking'])) : '';
			$options['google_analytics_half_disable'] = isset($_POST['siteseo_options']['half_disable']);
			$options['google_analytics_opt_out_edit_choice'] = isset($_POST['siteseo_options']['opt_edit_choices']);
			$options['google_analytics_opt_out_msg'] = isset($_POST['siteseo_options']['opt_msg']) ? wp_kses_post(wp_unslash($_POST['siteseo_options']['opt_msg'])) : 'We use cookies to enhance your experience.';
			$options['google_analytics_opt_out_msg_ok'] = isset($_POST['siteseo_options']['opt_msg_ok']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['opt_msg_ok'])) : 'Accept';
			$options['google_analytics_opt_out_msg_edit'] = isset($_POST['siteseo_options']['opt_edit_btn']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['opt_edit_btn'])) : 'Manage cookies';
			$options['google_analytics_opt_out_msg_close'] = isset($_POST['siteseo_options']['opt_close']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['opt_close'])) : 'X';
			$options['google_analytics_cb_exp_date'] = isset($_POST['siteseo_options']['cd_exp_date']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cd_exp_date'])) : '30';
			$options['google_analytics_cb_pos'] = isset($_POST['siteseo_options']['cd_pos']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cd_pos'])) : 'center';
			$options['google_analytics_cb_txt_align'] = isset($_POST['siteseo_options']['cd_txt_align']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cd_txt_align'])) : 'center';
			$options['google_analytics_cb_width'] = isset($_POST['siteseo_options']['cd_width']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cd_width'])) : '100%';
			$options['google_analytics_cb_scheme'] = isset($_POST['siteseo_options']['google_analytics_cb_scheme']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['google_analytics_cb_scheme'])) : '';

			// Colors
			$options['google_analytics_cb_backdrop'] = isset($_POST['siteseo_options']['cd_backdrop']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cd_backdrop'])) : '';
			$options['google_analytics_cb_backdrop_bg'] = isset($_POST['siteseo_options']['backdrop_bg']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['backdrop_bg'])) : '';
			$options['google_analytics_cb_bg'] = isset($_POST['siteseo_options']['cookiesbar_bg']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cookiesbar_bg'])) : '';
			$options['google_analytics_cb_txt_col'] = isset($_POST['siteseo_options']['cookiebar_txt']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['cookiebar_txt'])) : '';
			$options['google_analytics_cb_lk_col'] = isset($_POST['siteseo_options']['line_co']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['line_co'])) : '';
			$options['google_analytics_cb_btn_bg'] = isset($_POST['siteseo_options']['primary_btn_bg']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['primary_btn_bg'])) : '';
			$options['google_analytics_cb_btn_bg_hov'] = isset($_POST['siteseo_options']['primary_btn_bg_hov']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['primary_btn_bg_hov'])) : '';
			$options['google_analytics_cb_btn_col'] = isset($_POST['siteseo_options']['primary_btn_txt']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['primary_btn_txt'])) : '';
			$options['google_analytics_cb_btn_col_hov'] = isset($_POST['siteseo_options']['primary_btn_txt_hov']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['primary_btn_txt_hov'])) : '';
			$options['google_analytics_cb_btn_sec_bg'] = isset($_POST['siteseo_options']['sec_btn_bg']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['sec_btn_bg'])) : '';
			$options['google_analytics_cb_btn_sec_bg_hov'] = isset($_POST['siteseo_options']['sec_btn_bg_hov']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['sec_btn_bg_hov'])) : '';
			$options['google_analytics_cb_btn_sec_col'] = isset($_POST['siteseo_options']['sec_btn_txt']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['sec_btn_txt'])) : '';
			$options['google_analytics_cb_btn_sec_col_hov'] = isset($_POST['siteseo_options']['sec_btn_txt_hov']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['sec_btn_txt_hov'])) : '';
		}

		update_option('siteseo_google_analytics_option_name', $options);
	}

}
settings/dashboard.php000064400000042402151526415240011053 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Dashboard{

	static function dashboard_tab(){
		global $siteseo;
		
		$pro = get_option('siteseo_pro_options');
		$options = $siteseo->setting_enabled;

		$titles_meta_toggle = isset($options['toggle-titles']) ? $options['toggle-titles'] : '';
		$sitemap_toggle = isset($options['toggle-xml-sitemap']) ? $options['toggle-xml-sitemap'] : '';
		$social_toggle = isset($options['toggle-social']) ? $options['toggle-social'] : '';
		$advanced_toggle = isset($options['toggle-advanced']) ? $options['toggle-advanced'] : '';
		$analytics_toggle = isset($options['toggle-google-analytics']) ? $options['toggle-google-analytics'] : '';
		$indexing_toggle = isset($options['toggle-instant-indexing']) ? $options['toggle-instant-indexing'] : '';

		//pro-features
		$toggle_localBusiness = isset($pro['toggle_state_local_buz']) ? $pro['toggle_state_local_buz'] : '';
		$toggle_easy_digital = isset($pro['toggle_state_easy_digital']) ? $pro['toggle_state_easy_digital'] : '';
		$toggle_woocommerce  = isset($pro['toggle_state_woocommerce']) ? $pro['toggle_state_woocommerce'] : '';
		$toggle_structured_data = isset($pro['toggle_state_stru_data']) ? $pro['toggle_state_stru_data'] : '';
		$toggle_state_redirect = isset($pro['toggle_state_redirect_monitoring']) ? $pro['toggle_state_redirect_monitoring'] : '';
		$toggle_state_google_news = isset($pro['toggle_state_google_news']) ? $pro['toggle_state_google_news'] : '';
		$toggle_state_video_sitemap = isset($pro['toggle_state_video_sitemap']) ? $pro['toggle_state_video_sitemap'] : '';
		$toggle_state_llm_txt = isset($pro['toggle_state_llm_txt']) ? $pro['toggle_state_llm_txt'] : '';

		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		$pro_nonce = wp_create_nonce('siteseo_pro_toggle_nonce');

		$siteseo_dashboard_img = SITESEO_ASSETS_URL.'/img/seo-get-started.jpg';
		$siteseo_loginizer_product = SITESEO_ASSETS_URL.'/img/loginizer_product.png';
		
		echo'<div id="siteseo-root">';

		Util::admin_header();
		$dismissed_intro = get_option('siteseo_dismiss_intro', 0);

		echo'<div id="siteseo-dashbord">';
		
		if(empty($dismissed_intro) && !defined('SITEPAD')){
			echo '<div class="siteseo-dashbord-intro">
			   <div class="siteseo-text-content">
					<h2>'.esc_html__('HOW-TO GET STARTED', 'siteseo').'</h2><h1>'.esc_html__('Welcome to SiteSEO!', 'siteseo').'</h1>
					<p>'.esc_html__('Launch our installation wizard to quickly and easily configure the basic SEO settings for your site. Cant find the answers to your questions? Write us at support@siteseo.io. A happiness engineer will be happy to help you.', 'siteseo').'</p>
					<div class="siteseo-buttons">
					<a class="get-started" href="?page=siteseo-onboarding">'.esc_html__('Get started', 'siteseo').'</a>
					<a class="dismiss" id="siteseo-dismiss-get-started" href="#">'.esc_html__('Dismiss', 'siteseo').'</a>
					</div>
				</div>
				<div class="siteseo-image-content"><img alt="'.esc_html__('Illustration of a megaphone with various icons representing SEO and digital marketing', 'siteseo').'" height="470" src="'.esc_url($siteseo_dashboard_img).'" width="470"/>
				</div>
			</div>';
		}

			echo '<div class="siteseo-dashbord-content">
				<section class="siteseo-dashboard-features">
					<h2>'.esc_html__('Manage SiteSEO Features', 'siteseo').'</h2></br/>
					<div class="siteseo-dashbord-container">
						<div class="siteseo-card">
							<div class="siteseo-card-body">
								<span class="dashicons dashicons-edit-large siteseo-card-icon"></span>
								<h3>'.esc_html__('Titles &amp; Metas', 'siteseo').'</h3>
								<p>'.esc_html__('Manage all your titles and metas for post types, taxonomies more...', 'siteseo').'</p>
							</div>
							<div class="siteseo-card-footer">
								<a href="admin.php?page=siteseo-titles">'.esc_html__('Settings', 'siteseo').'</a>';
								Util::render_toggle('Titles & Metas -SiteSEO', 'titles_meta_toggle', $titles_meta_toggle, $nonce, true);
						   echo'</div>
						</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-networking siteseo-card-icon"></span>
					<h3>'.esc_html__('XML & HTML Sitemaps', 'siteseo').'</h3>
					<p>'.esc_html__('Manage your XML - Image - Video- Taxonomies - HTML Sitemap more...', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-sitemaps">'.esc_html__('Settings', 'siteseo').'</a>';
					Util::render_toggle('Sitemaps - SiteSEO', 'sitemap_toggle', $sitemap_toggle, $nonce,true);
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-share siteseo-card-icon"></span>
					<h3>'.esc_html__('Social Networks', 'siteseo').'</h3>
					<p>'.esc_html__('Open Graph, X Card, Google Knowledge Graph and more...', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-social">'.esc_html__('Settings','siteseo').'</a>';
					Util::render_toggle('Social - SiteSEO', 'social_toggle', $social_toggle, $nonce,true);
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-performance siteseo-card-icon"></span>
					<h3>'.esc_html__('Analytics', 'siteseo').'</h3>
					<p>'.esc_html__('Track everything about your visitors with Analytics/Matomo more...', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-analytics">'.esc_html__('Settings','siteseo').'</a>';
					Util::render_toggle('Analytics - SiteSEO', 'analytics_toggle', $analytics_toggle, $nonce,true);
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-superhero siteseo-card-icon"></span>
					<h3>'.esc_html__('Instant Indexing','siteseo').'</h3>
					<p>'.esc_html__('Ping Google & Bing to quickly index your content. Updated and  remove submit URLs','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-instant-indexing">'.esc_html__('Settings','siteseo').'</a>';
					Util::render_toggle('Instant indexing - SiteSEO', 'indexing_toggle', $indexing_toggle, $nonce,true);
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-format-gallery siteseo-card-icon"></span>
					<h3>'.esc_html__('Image SEO','siteseo').'</h3>
					<p>'.esc_html__('Optimize your images for SEO. Configure advanced settings more...','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-advanced">'.esc_html__('Settings','siteseo').'</a>';
					Util::render_toggle('Advanced - SiteSEO', 'advanced_toggle', $advanced_toggle, $nonce,true);
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-upload siteseo-card-icon"></span>
					<h3>'.esc_html__('Tools', 'siteseo').'</h3>
					<p>'.esc_html__('Import/Export plugin settings from site to site. Reset settings more...', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">
					<a href="admin.php?page=siteseo-tools">'.esc_html__('Settings', 'siteseo').'</a>
					<div class="siteseo-toggle-container">
					</div>
				</div>
			</div>';
			if(!defined('SITEPAD')){
				echo'<div class="siteseo-card">
					<div class="siteseo-card-body">
						<span class="dashicons dashicons-cart siteseo-card-icon"></span>
						<h3>'.esc_html__('WooCommerces SEO','siteseo'),'</h3>
						<p>'.esc_html__('Add meta tags required for WooCommerce SEO','siteseo').'</p>
					</div>
					<div class="siteseo-card-footer">';
						if(defined('SITESEO_PRO_VERSION')){
							echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings','siteseo').'</a>';
						} else{
							echo'<div class="siteseo-pro-badge">Pro</div>';
						}
						
						if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
							\SiteSEOPro\Settings\Util::render_toggle('woocommerce', $toggle_woocommerce, $pro_nonce, true);
						} 
					echo'</div></div>';
			

			echo '<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-money-alt siteseo-card-icon"></span>
					<h3>'.esc_html__('Easy Digital Downloads', 'siteseo').'</h3>
					<p>'.esc_html__('Add meta tags required for Easy Digitial Downloads SEO', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings','siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('edd', $toggle_easy_digital, $pro_nonce,true);
					}
				echo'</div></div>';
			}
			echo '<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-code-standards siteseo-card-icon"></span>
					<h3>'.esc_html__('Page Speed', 'siteseo').'</h3>
					<p>'.esc_html__('Enhance Your Website Performance with PageSpeed Insights','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else {
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
				echo'</div>
			</div>

			<div class="siteseo-card">
				'.((time() < strtotime('30 November 2025')) ? '<span class="siteseo-feature-update-badge">Updated</span>' : '') .'
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-list-view siteseo-card-icon"></span>
					<h3>'.esc_html__('Structured Data','siteseo').'</h3>
					<p>'.esc_html__('Enhance Search Visibility with Structured Data Optimization','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('structured', $toggle_structured_data, $pro_nonce,true);
					}
				echo'</div>
			</div>

			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-location siteseo-card-icon"></span>
					<h3>'.esc_html__('Local Business', 'siteseo').'</h3>
					<p>'.esc_html__('Optimize Your Online Presence for Local Business Success', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo '<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('local', $toggle_localBusiness, $pro_nonce, true);
					}
				echo'</div>
			</div>
			
			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-editor-unlink siteseo-card-icon"></span>
					<h3>'.esc_html__('Redirections / 404 monitoring','siteseo').'</h3>
					<p>'.esc_html__('Track 404 errors and set up redirects to improve user experience and SEO.','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('404_monitoring', $toggle_state_redirect, $pro_nonce, true);
					}
				echo'</div>
			</div>
			
			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-index-card siteseo-card-icon"></span>
					<h3>'.esc_html__('Google News','siteseo').'</h3>
					<p>'.esc_html__('Generate and manage a Google News sitemap to ensure your news articles get indexed quickly.','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('google_news', $toggle_state_google_news, $pro_nonce, true);
					}
				echo'</div>
			</div>
			
			<div class="siteseo-card">
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-format-video siteseo-card-icon"></span>
					<h3>'.esc_html__('Video Sitemap','siteseo').'</h3>
					<p>'.esc_html__('Create and manage a video sitemap to help search engines index your video content efficiently.','siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('video_sitemap', $toggle_state_video_sitemap, $pro_nonce, true);
					}
				echo'</div>
			</div>

			<div class="siteseo-card">
				'.((time() < strtotime('30 November 2025')) ? '<span class="siteseo-feature-new-badge">New</span>' : '') .'
				<div class="siteseo-card-body">
					<span class="dashicons dashicons-media-text siteseo-card-icon"></span>
					<h3>'.esc_html__('LLMs txt', 'siteseo').'</h3>
					<p>'.esc_html__('Generate an llms.txt file with a single click to help AI crawlers better understand, index, and represent your business accurately.', 'siteseo').'</p>
				</div>
				<div class="siteseo-card-footer">';
					if(defined('SITESEO_PRO_VERSION')){
						echo'<a href="admin.php?page=siteseo-pro-page">'.esc_html__('Settings', 'siteseo').'</a>';
					} else{
						echo'<div class="siteseo-pro-badge">Pro</div>';
					}
					
					if(class_exists('\SiteSEOPro\Settings\Util') && method_exists('\SiteSEOPro\Settings\Util', 'render_toggle')){
						\SiteSEOPro\Settings\Util::render_toggle('llm_txt', $toggle_state_llm_txt, $pro_nonce, true);
					}
				echo'</div>
			</div>';

	echo'</div></section>';
	
	if(!defined('SITEPAD')){
		echo'<section class="siteseo-dashboard-extras">';
			if(defined('SITESEO_PRO_VERSION') && defined('SITESEO_PRO_AI_BUY')){
				do_action('siteseo_pro_show_ai_tokens_sidebar');
			}
			echo '<div class="siteseo-need-help">
				<p>Quick Access</p>
				<div class="siteseo-quick-links">
					<div class="siteseo-quick-access-item">
						<span class="dashicons dashicons-format-status"></span>
						<a href="https://softaculous.deskuss.com/open.php?topicId=22" target="_blank">Support</a>
					</div>
					<div class="siteseo-quick-access-item">
						<span class="dashicons dashicons-media-document"></span>
						<a href="https://siteseo.io/docs/" target="_blank">Documentation</a>
					</div>
					<div class="siteseo-quick-access-item">
						<span class="dashicons dashicons-feedback"></span>
						<a href="https://softaculous.deskuss.com/open.php?topicId=22" target="_blank">Feedback</a>
					</div>
					<div class="siteseo-quick-access-item">
						<span class="dashicons dashicons-star-filled" style="color:#FFD700;"></span><a href="https://wordpress.org/support/plugin/siteseo/reviews/?rate=5#new-post" target="_blank">Rate Us</a>
					</div>
				</div>
			</div>
			<div class="siteseo-admin-softaculous-branding">SiteSEO - A Softaculous Product</div>';

			if(!defined('SITEPAD') && !defined('SITESEO_PRO_VERSION')){
				self::pro_upsell();
			}

			echo '</section>';
	}

	echo '</div></div></div>';
	}

	static function pro_upsell(){

		$features = [
			'Search Statistics',
			'Advanced Sitemaps',
			'Redirection Management',
			'AI-Generations Titles & Descriptions',
			'LLMs.txt Support',
			'and More…',
		];

		echo '<div class="siteseo-promo-modern-card">
			<div class="siteseo-promo-header-group">
			<h3 class="siteseo-promo-title">SiteSEO</h3>
			<span class="siteseo-promo-badge-pro">Pro</span>
			</div>

			<p class="siteseo-promo-desc">'.esc_html__('Unlock advanced performance features.', 'siteseo').'</p>

			<ul class="siteseo-promo-feature-list">';
			foreach($features as $feature){
				echo '<li class="siteseo-promo-feature-item">
					<div class="siteseo-promo-check-circle">
						<div class="siteseo-promo-check-icon"></div>
					</div>
					'.esc_html($feature).'
				</li>';
			}
			echo '</ul>

			<a href="https://siteseo.io/pricing/?utm_source=plugin_settings" class="siteseo-promo-btn-main" target="_blank">
				<span class="siteseo-promo-btn-text">'.esc_html__('Upgrade to Pro', 'siteseo').'</span>
				<span class="siteseo-promo-arrow">&rarr;</span>
			</a>
		</div>';
	}

}
settings/tools.php000064400000012776151526415240010277 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Tools{

	static function menu(){

		echo '<div id="siteseo-root">';
		
		Util::admin_header();

		$plugins = Util::importable_plugins();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">
				<span id="siteseo-tab-title"><strong>'.esc_html__('Tools - SiteSEO','siteseo').'</strong></span><br/><br/>
				<span class="line"></span>
				<div style="siteseo-tools-page">';
					if(!defined('SITEPAD')){
						echo '<h3>'.esc_html__('Import Settings From Other Plugins','siteseo').'</h3>
						<div class="siteseo_wrap_label">
							<p class="description">'.esc_html__('Import posts and terms metadata from the specified source', 'siteseo').'</p>
						</div>

						<p><select id="siteseo-plugin-selector">
							<option value="none">'.esc_html__('Select an option', 'siteseo').'</option>';
							foreach($plugins as $plugin => $name){
								$plugin_slug = explode('/', $plugin);
								$plugin = $plugin_slug[0];

								echo '<option value="'. esc_attr($plugin) . '-migration-tool">'.esc_html($name).'</option>';
							}

						echo '</select></p>
						<p class="description">' . esc_html__('You don\'t need to enable the selected SEO plugin to run the import.', 'siteseo').'</p>';
					
						foreach($plugins as $plugin =>$name){
							self::display_plugins($plugin, $name);
						}

						echo '<span class="line"></span>';
					}
					
					echo '<h3>'.esc_html__('Export plugin settings','siteseo').'</h3>
					<div class="siteseo_wrap_label">
						<p class="description">'.esc_html__('Export the plugin settings for this site as a .json file, making it easy to import the configuration into another site.', 'siteseo').'</p>
					</div>

					<div class="siteseo_wrap_label">
						<button class="btn btnSecondary" id="siteseo-export-btn">'.esc_html__('Export', 'siteseo').'</button>
					</div>
					<span class="line"></span>
					
					<h3>'.esc_html__('Import plugin settings', 'siteseo').'</h3>
					<div class="siteseo_wrap_label">
						<p class="description">'.esc_html__('Import the plugin settings from a .json file. You can obtain this file by exporting the settings from another site using the form above.','siteseo').'</p>
					</div>
							
					<div class=siteseo_wrap_label>
						<input type="file" id="siteseo-import-file" accept=".json" />
					</div>

					<div class="siteseo_wrap_label">
						<button class="brn btnSecondary" id="siteseo-import-btn">'. esc_html__('Import', 'siteseo') .'</button>
					</div>
					
					<span class="line"></span>
					
					<h3>'.esc_html__('Reset All Settings', 'siteseo').'</h3>
					<div class="siteseo_wrap_label"><div class="siteseo-notice is-warning">
						<span id="dashicons-warning" class="dashicons dashicons-info"></span>&nbsp;
						<div><p>'.
						/* translators: placeholders are just <strong> tag */ 
						wp_kses_post(sprintf(__('%1$s WARNING: %2$s Delete all options related to this plugin in your database.','siteseo'), '<strong>', '</strong>')).'</p></div>
					</div></div>
					<button class="btn btnSecondary" id="siteseo-reset-settings">'.esc_html__('Reset settings', 'siteseo').'</button>
	
			</div>
			</form></div>';
	}
	
	static function display_plugins($plugin,$name){
		$seo_title = 'SiteSEO';
		$plugin_slug = explode('/', $plugin);
		$plugin = $plugin_slug[0];
		
		echo '<div id="'.esc_attr($plugin).'-migration-tool" class="postbox siteseo-section-tool">
		<div class="inside">
		<h3>'. /* translators: %s represents the import posts and terms */ 
		sprintf(esc_html__('Import posts and terms (if available) metadata from %s', 'siteseo'), esc_html($name)).'</h3>
		<p>'. esc_html__('By clicking Migrate, we\'ll import:', 'siteseo').'</p>
		<ul>
			<li>'. esc_html__('Title tags', 'siteseo') .'</li>
			<li>'. esc_html__('Meta description', 'siteseo') .'</li>
			<li>'. esc_html__('Facebook Open Graph tags (title, description and image thumbnail)', 'siteseo') .'</li>
			<li>'. esc_html__('Twitter tags (title, description and image thumbnail)', 'siteseo') .'</li>
			<li>'. esc_html__('Meta Robots (noindex, nofollow...)', 'siteseo') .'</li>
			<li>'.esc_html__('Canonical URL', 'siteseo').'</li>';

			if($plugin !='slim-seo' && $plugin != 'surerank'){
				echo '<li>'. esc_html__('Focus / target keywords', 'siteseo') .'<li>';
			}
			
			if($plugin != 'all-in-one-seo-pack' && $plugin !='slim-seo' && $plugin != 'surerank'){
				echo '<li>'. esc_html__('Primary category', 'siteseo') .'</li>';
			}
			
			if('autodescription' == $plugin || 'all-in-one-seo-pack' == $plugin || 'wp-seopress' == $plugin){
				echo '<li>'. esc_html__('Redirect URL', 'siteseo') .'</li>';
			}

			echo '</ul>
					<div class="siteseo_wrap_label">						
						<div class="siteseo-notice is-warning">
							<span id="dashicons-warning" class="dashicons dashicons-warning"></span>&nbsp;
								<p>'. 
								/* translators: %s represents the degree of severity */ 
								wp_kses_post(sprintf(__('<strong>WARNING:</strong> Migration will delete / update all <strong>%1$s posts and terms metadata</strong>. Some dynamic variables will not be interpreted. We do <strong>NOT delete any %2$s data</strong>.', 'siteseo'), esc_html($seo_title), esc_html($name))). '
								</p>
						</div>
					</div>
						
					<button id="siteseo-'.esc_attr($plugin).'-migrate" type="button" class="btn btnSecondary">' 
						. esc_html__('Import now', 'siteseo').'</button><span class="spinner"></span><div class="log"></div>
					</div>
				</div>';
		}

}
settings/util.php000064400000006662151526415240010111 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Util{

	static function clean_text($text){
		return sanitize_text_field(wp_unslash($text));
	}

	static function clean_url($url){
		if(is_array($url)){
			return map_deep(wp_unslash($url), 'sanitize_url');
		}

		return sanitize_url(wp_unslash($url));
	}

	static function render_toggle($title, $toggle_key, $toggle_state, $nonce, $label = false){
		$is_active = $toggle_state ? 'active' : '';
		$state_text = $toggle_state ? 'Disable' : 'Enable';

		// for dashbord screen
		if(!empty($label)){
			echo '<div class="siteseo-toggle-cnt">
				<div class="siteseo-toggle-Sw '.esc_attr($is_active).'" id="siteseo-toggleSw-' . esc_attr($toggle_key) . '" data-nonce="'.esc_attr($nonce).'" data-toggle-key="'.esc_attr($toggle_key).'" data-action="siteseo_save_'.esc_attr($toggle_key).'"></div>
				<input type="hidden" name="siteseo_options['.esc_attr($toggle_key) . ']" id="'.esc_attr($toggle_key).'" value="'.esc_attr($toggle_state).'">
			</div>';
		}else{

			echo '<div class="siteseo-toggle-cnt">
				<span id="siteseo-tab-title"><strong>'.esc_html($title).'</strong></span>
				<div class="siteseo-toggle-Sw '.esc_attr($is_active).'" id="siteseo-toggleSw-'.esc_attr($toggle_key).'" data-nonce="' . esc_attr($nonce) . '" data-toggle-key="'.esc_attr($toggle_key).'" data-action="siteseo_save_'.esc_attr($toggle_key).'"></div>
				<span id="siteseo-arrow-icon" class="dashicons dashicons-arrow-left-alt siteseo-arrow-icon"></span>
				<p class="toggle_state_'.esc_attr($toggle_key).'">'.esc_html($state_text).'</p>
				<input type="hidden" name="siteseo_options['.esc_attr($toggle_key).']" id="'.esc_attr($toggle_key).'" value="'.esc_attr($toggle_state).'">
			</div>';
		}
	}
	
	static function admin_header(){
		echo '<div class="siteseo-navbar">
			<div class="logo">
				<img alt="'.esc_html__('siteseo logo', 'siteseo').'" height="30" src="'. esc_url(SITESEO_ASSETS_URL).'/img/logo-24.svg'.'" width="40"/>
				<div class="siteseo-breadcrumb">
					<a href="#">'.esc_html__('Home', 'siteseo').'</a>
					<span>/</span>
					<a class="active" href="">'.esc_html(get_admin_page_title()).'</a>
				</div>
			</div>';
			
			echo'<div class="links">
					<span class="siteseo-header-version-badge">v'.esc_html(SITESEO_VERSION).'</span>
					<a target="_blank" href="https://siteseo.io/docs/">'.esc_html__('Docs', 'siteseo').'</a>';
					
					if(!defined('SITEPAD')){
						echo'<a target="_blank" class="support" href="https://softaculous.deskuss.com/open.php?topicId=22">'.esc_html__('Support', 'siteseo').'</a>';
					}
				echo'</div>
			</div>';
	}
	
	static function importable_plugins(){
		return [
			'wordpress-seo/wp-seo.php' => 'Yoast SEO',
			'all-in-one-seo-pack/all_in_one_seo_pack.php' => 'All In One SEO',
			'autodescription/autodescription.php' => 'The SEO Framework',
			'seo-by-rank-math/rank-math.php' => 'Rank Math',
			'wp-seopress/seopress.php' => 'SEOPress',
			'slim-seo/slim-seo.php' => 'Slim SEO',
			'surerank/surerank.php' => 'Surerank'
		];
	}

	static function submit_btn($value = ''){
		echo '<div class="siteseo-submit-button"><input type="submit" id="submit" name="submit" value="'.esc_attr($value ?: 'Save changes') . '" class="submit-button"></div>';
	}
	
	static function extract_content($input){

		if(preg_match('/content=["\']([^"\']+)["\']/', $input, $matches)){
			return $matches[1];
		}
		
		return $input;
	}
}settings/onboarding.php000064400000047771151526415240011264 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class OnBoarding{
	
	static $current_step = '';
	static $import_options = [];
	static $steps = [];
	static $current_step_no = 1;

	static function init(){
		if(wp_doing_ajax()){
			return;
		}
		
		self::$steps = [
			'your-site' => [
				'title' => 'Your Site',
				'desc' => 'Your site and social data',
				'fn' => '\SiteSEO\Settings\OnBoarding::site_page',
			],
			'indexing' => [
				'title' => 'Indexing',
				'desc' => 'Select post type indexing',
				'fn' => '\SiteSEO\Settings\OnBoarding::indexing_page',
			],
			'advanced' => [
				'title' => 'Advanced',
				'desc' => 'URL configuration',
				'fn' => '\SiteSEO\Settings\OnBoarding::advanced_page',
			],
			'ready' => [
				'title' => 'Ready',
				'desc' => 'All set now!',
				'fn' => '\SiteSEO\Settings\OnBoarding::ready_page',
			],
		];
		
		$active_plugins = get_option('active_plugins', []);
		$importable_plugins = Util::importable_plugins();
		$importable_plugins = array_keys($importable_plugins);
		
		$importable_found = array_intersect($active_plugins, $importable_plugins);
		
		if(!empty($importable_found)){
			$import_step = [
				'import' => [
					'title' => 'Import',
					'desc' => 'Importing meta data',
					'fn' => '\SiteSEO\Settings\OnBoarding::import_page',
				]
			];
			
			self::$steps = array_merge($import_step, self::$steps);
			self::$import_options = $importable_found;
		}
		
		self::$current_step = !empty($_REQUEST['step']) ? sanitize_text_field(wp_unslash($_REQUEST['step'])) : '';

		remove_all_actions('admin_notices');
		remove_all_actions('all_admin_notices');
		remove_all_actions('network_admin_notices');
		add_action('admin_menu', '\SiteSEO\Settings\OnBoarding::add_to_menu');
		add_action('admin_init', '\SiteSEO\Settings\OnBoarding::page');
	}

	static function enqueue_assets(){
		wp_enqueue_media();
		wp_enqueue_script('siteseo-onboarding', SITESEO_ASSETS_URL . '/js/onboarding.js', ['jquery'], SITESEO_VERSION, true);
		wp_enqueue_style('siteseo-onboarding' , SITESEO_ASSETS_URL . '/css/onboarding.css', [], SITESEO_VERSION);
		wp_add_inline_script('siteseo-onboarding', "let siteseo_onboarding = ".wp_json_encode([
			'nonce' => wp_create_nonce('siteseo_admin_nonce'),
			'ajax_url' => admin_url('admin-ajax.php'),
		]));
	}
	
	static function add_to_menu(){
		add_submenu_page('', __('SiteSEO Onboarding', 'siteseo'), 'Onboarding', 'manage_options', 'siteseo-onboarding', 'SiteSEO\Settings\Onboarding::wizard');
	}
	
	static function page(){
		self::enqueue_assets();
		
		ob_start();

	?><!DOCTYPE html>
<html <?php language_attributes();?>>
<?php echo'<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>'.esc_html__('SiteSEO OnBoarding', 'siteseo').'</title>';
wp_print_head_scripts();
wp_print_styles('siteseo-onboarding');
	
echo '</head>
<body>';
	self::wizard();
	if(function_exists('wp_print_media_templates')){
		wp_print_media_templates();
	}
	wp_print_footer_scripts();
	wp_print_scripts('siteseo-onboarding');
	echo '</body>
</html>';
		die();
	}
	
	static function wizard(){

		echo '<div id="siteseo-onboarding-root">
	<div class="siteseo-onboarding-nav-wrapper">
	<nav>
		<div class="content">
		<div class="header">
			<img src="'.esc_url(SITESEO_ASSETS_URL) .'/img/siteseo-white.png" height="40"/>
			<a href="'.esc_url(admin_url('?page=siteseo')).'" title="'.esc_attr__('Exit to SiteSEO Dashboard', 'siteseo').'"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#fff"><path d="M200-120q-33 0-56.5-23.5T120-200v-160h80v160h560v-560H200v160h-80v-160q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm220-160-56-58 102-102H120v-80h346L364-622l56-58 200 200-200 200Z"/></svg></a>
		</div>';

		$step_count = 1;
		echo '<div class="steps">';
		foreach(self::$steps as $step_slug => $step){
			echo '<div class="step">
				<div class="step-milestone" data-step="'.esc_attr($step_count).'" data-step-slug="'.esc_attr($step_slug).'"></div>
				<div class="step-info"><span>'.esc_html($step['title']).'</span><span class="description">'.esc_html($step['desc']).'</span></div>
			</div>';
			$step_count++;
		}
		echo '
		</div>
		</div>
		<div class="footer">A Softaculous Product</div>
	</nav>
	</div>
	<main>
		<div class="siteseo-onboarding-content">';
		self::welcome_page();
		
		foreach(self::$steps as $step){
			call_user_func($step['fn']);
			self::$current_step_no++; // increasing the step number after we have rendered the step page.
		}

		echo '</div>
	
	</main>
</div>';

	}

	static function welcome_page(){
		
		$is_active = empty(self::$current_step) ? 'siteseo-step-active' : '';
		
		echo '<div class="siteseo-step-page siteseo-step-is-welcome '.esc_attr($is_active).'" data-step="welcome">
			<h1>'.esc_html__('Welcome to the SiteSEO Setup Wizard', 'siteseo').'</h1>
			<p>'.esc_html__('This wizard will guide you through setting up SiteSEO and help you get started in no time.', 'siteseo').'</p>
			<button class="siteseo-btn primary" id="siteseo-onboarding-begin" style="margin-top:20px">'.esc_html__('Let\'s begin!', 'siteseo').'</button>
		</div>';
		
	}
	
	static function import_page(){
		$is_active = !empty(self::$current_step) && self::$current_step == 'import' ? 'siteseo-step-active' : '';

		echo '<div class="siteseo-step-page '.esc_attr($is_active).'" data-step="import">
		<span>Step '.esc_html(self::$current_step_no).' of '.count(self::$steps).'</span>
		<h1>'.esc_html__('Import data from your current SEO plugin', 'siteseo').'</h1>
		<p>'.esc_html__('SiteSEO has detected the presence of other SEO plugins. To ensure a smooth transition, please select the plugins you wish to import SEO data from', 'siteseo').'</p>
		<div class="siteseo-onboarding-import-plugins">';
			$importable_plugins = Util::importable_plugins();

			echo '<form><div class="siteseo-radio-input">';
			foreach(self::$import_options as $plugin){
				$id = strtolower(str_replace(' ', '-', $plugin));
				echo '<input type="radio" name="plugin_name" value="'.esc_attr($id).'" id="'.esc_attr($id).'"/>
				<label for="'.esc_attr($id).'">'.esc_html($importable_plugins[$plugin]).'</label>';
			}
			echo '</div>
			<div class="siteseo-onboarding-import-info">
				<details>
					<summary>'.esc_html__('What will be imported?', 'siteseo').'</summary>
					<ul>
						<li>'. esc_html__('Title tags', 'siteseo') .'</li>
						<li>'. esc_html__('Meta description', 'siteseo') .'</li>
						<li>'. esc_html__('Facebook Open Graph tags (title, description and image thumbnail)', 'siteseo') .'</li>
						<li>'. esc_html__('Twitter tags (title, description and image thumbnail)', 'siteseo') .'</li>
						<li>'. esc_html__('Meta Robots (noindex, nofollow...)', 'siteseo') .'</li>
						<li>'. esc_html__('Canonical URL', 'siteseo').'</li>
						<li>'. esc_html__('Focus / target keywords', 'siteseo') .'</li>
					</ul>
				</details>
				<button class="siteseo-btn primary" id="siteseo-do-import">Import</button>
				<p class="siteseo-onboarding-msg"></p>
			</div>
			</form>
			<div class="siteseo-onboarding-content-footer">
			<button class="siteseo-skip-step siteseo-btn secondary">'.esc_html__('Skip Step', 'siteseo').'</button><button class="siteseo-btn primary siteseo-skip-step">'.esc_html__('Next Step', 'siteseo').'</button>
			</div>
		</div>
		</div>';
	}
	
	static function site_page(){
		$title_options = get_option('siteseo_titles_option_name', []);
		$social_options = get_option('siteseo_social_option_name', []);

		$site_name = !empty($title_options['titles_home_site_title']) ? $title_options['titles_home_site_title'] : '%%sitetitle%%';
		$alt_site_name = !empty($title_options['titles_home_site_title_alt']) ? $title_options['titles_home_site_title_alt'] : '';
		$site_type = !empty($social_options['social_knowledge_type']) ? $social_options['social_knowledge_type'] : '';
		$org_name = !empty($social_options['social_knowledge_name']) ? $social_options['social_knowledge_name'] : '';
		$org_img = !empty($social_options['social_knowledge_img']) ? $social_options['social_knowledge_img'] : '';
		$fb_url	= !empty($social_options['social_accounts_facebook']) ? $social_options['social_accounts_facebook'] : '';
		$x_account = !empty($social_options['social_accounts_twitter']) ? $social_options['social_accounts_twitter'] : '';
		$additional_url = !empty($social_options['social_accounts_additional']) ? implode("\n", $social_options['social_accounts_additional']) : '';
		
		$is_active = !empty(self::$current_step) && self::$current_step == 'your-site' ? 'siteseo-step-active' : '';
		echo '<div class="siteseo-step-page '.esc_attr($is_active).'" data-step="your-site">
		<span>Step '.esc_html(self::$current_step_no).' of '.count(self::$steps).'</span>
		<h1>Your Site: '.esc_html(get_bloginfo('name')).'</h1>
		<p>'.esc_html__('We need some basic information about your site, so we can built up the knowledge graph', 'siteseo').'</p>
		<form>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Website Name', 'siteseo').'</label>
				<input type="text" name="website_name" value="'.esc_attr($site_name).'"/>
				<p class="siteseo-input-description">'.esc_html__('Enter the name of your site as it should appear in search results, %%sitetitle%% is a dynamic variable for your site title', 'siteseo').'</p>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Altername sitename', 'siteseo').'</label>
				<input type="text" name="alternate_site_name" value="'.esc_attr($alt_site_name).'" placeholder="Alternate site name"/>
				<p class="siteseo-input-description">'.esc_html__('The website\'s alternate name, like a common acronym or shorter version, if applicable.', 'siteseo').'</p>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Is your site about an Organization or a Person?', 'siteseo').'</label>
				<select type="text" name="site_type">
					<option value="Person" '.selected($site_type, 'Person', false).'>Person</option>
					<option value="Organization" '.selected($site_type, 'Organization', false).'>Organization</option>
				</select>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Your/Organization name', 'siteseo').'</label>
				<input type="text" name="organization_name" placeholder="eg:. My Company Name" value="'.esc_attr($org_name).'"/>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Organization Logo', 'siteseo').'</label>
				<button id="siteseo-onboarding-img-holder">
				<img src="'.esc_url($org_img).'"/>
				<svg xmlns="http://www.w3.org/2000/svg" height="50px" viewBox="0 -960 960 960" width="50px" fill="#5f6368" style="'.(!empty($org_img) ? 'display:none;' : '').'"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg></button>
				<p class="siteseo-input-description">'.esc_html__('A square image is preferred, with a minimum size of 112x112 pixels.', 'siteseo').'</p>
				<input type="hidden" name="organization_logo" value="'.esc_url($org_img).'"/>
				<button class="siteseo-btn primary" id="siteseo-upload-org-img" style="align-self:flex-start">'.esc_html__('Select Image', 'siteseo').'</button>
			</div>
			<h4>Social Details</h4>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Facebook page URL', 'siteseo').'</label>
				<input type="text" name="social_fb" value="'.esc_url($fb_url).'" placeholder="eg: https://facebook.com/my-page-url"/>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('X Username', 'siteseo').'</label>
				<input type="text" name="social_x" value="'.esc_attr($x_account).'" placeholder="eg: @x_account"/>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Additional Accounts', 'siteseo').'</label>
				<textarea rows="3" name="social_additional" placeholder="eg:https://somesocial.com/my-page">'.esc_textarea($additional_url).'</textarea>
				<p class="siteseo-input-description">'.esc_html__('Enter 1 URL per line.', 'siteseo').'</p>
			</div>
			
			<div class="siteseo-onboarding-content-footer">
				<button class="siteseo-skip-step siteseo-btn secondary">'.esc_html__('Skip Step', 'siteseo').'</button><button class="siteseo-btn primary siteseo-save-n-continue">'.esc_html__('Save and Continue', 'siteseo').'<span class="siteseo-spinner"></span></button>
			</div>
		</form>
		</div>';
	}
	
	static function indexing_page(){
		$is_active = !empty(self::$current_step) && self::$current_step == 'indexing' ? 'siteseo-step-active' : '';
		$post_types = get_post_types(['public' =>  true, 'show_ui' => true], 'objects', 'and');
		unset($post_types['attachment']);
		
		$taxonomies = get_taxonomies(['public' =>  true, 'show_ui' => true], 'objects', 'and');

		echo '<div class="siteseo-step-page '.esc_attr($is_active).'" data-step="indexing">
		<span>Step '.esc_html(self::$current_step_no).' of '.count(self::$steps).'</span>
		<h1>Indexing</h1>
		<p>'.esc_html__('Let us know which parts of your website you’d like to be crawled.', 'siteseo').'</p>
		<form method="POST">
		<div class="siteseo-input-block">
			<label>'.esc_html__('Is your site under construction or live?', 'siteseo').'</label>
			<div class="siteseo-radiogroup">
				<label><input type="radio" name="site_status" value="underconstruction"/>Under Construction</label>
				<label><input type="radio" name="site_status" value="live" checked/>Live</label>
			</div>
			<p class="siteseo-input-description">'.esc_html__('If your site is under construction then Search Engines will be discouraged to crawl your site by adding noindex metatag attribute and sitemap will be disabled.', 'siteseo').'</p>
		</div>
		<div class="siteseo-live-site-options" style="margin-top:35px;">
			<p>'.esc_html__('Choose items to exclude from search results', 'siteseo').'</p>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Post Types', 'siteseo').'</label>
				<div class="siteseo-radiogroup">';
				if(!empty($post_types)){
				foreach($post_types as $post){
					echo '<div><input type="checkbox" name="post_types" value="'.esc_attr($post->name).'" id="post_type_'.esc_attr($post->name).'"/>
					<label for="post_type_'.esc_attr($post->name).'">'.esc_html($post->label).'</label>
					</div>';
				}

				echo '<p class="siteseo-input-description">'.esc_html__('Discourage search engines from indexing these post types.', 'siteseo').'</p>';
			} else {
				echo '<p class="siteseo-input-description">'.esc_html__('No post type found.', 'siteseo').'</p>';
			}
			
			//TODO:: Will need to add options for Archive as well
			echo '</div>
			</div>
			<div class="siteseo-input-block">
				<label>'.esc_html__('Taxonomies', 'siteseo').'</label>
				<div class="siteseo-radiogroup">';
				if(!empty($taxonomies)){
					foreach($taxonomies as $taxonomy){
						echo '<div><input type="checkbox" name="taxonomies" value="'.esc_attr($taxonomy->name).'" id="taxonomy_'.esc_attr($taxonomy->name).'"/>
						<label for="taxonomy_'.esc_attr($taxonomy->name).'">'.esc_html($taxonomy->label).'</label>
						</div>';
					}

					echo '<p class="siteseo-input-description">'.esc_html__('Discourage search engines from indexing these taxonomies.', 'siteseo').'</p>
					<p class="siteseo-input-description">'.esc_html__('Note: We strongly recommend disabling the indexing of tags to avoid potential duplicate content issues that could negatively impact your site\'s SEO.', 'siteseo').'</p>';
				} else {
					echo '<p class="siteseo-input-description">'.esc_html__('No taxonomy found.', 'siteseo').'</p>';
				}
			echo '</div>
			</div>
		</div>
		<div class="siteseo-onboarding-content-footer">
			<button class="siteseo-skip-step siteseo-btn secondary">'.esc_html__('Skip Step', 'siteseo').'</button><button class="siteseo-btn primary siteseo-save-n-continue">'.esc_html__('Save and Continue', 'siteseo').'<span class="siteseo-spinner"></span></button>
		</div>
		</form>
		</div>';
	}
	
	static function advanced_page(){
		$is_active = !empty(self::$current_step) && self::$current_step == 'advanced' ? 'siteseo-step-active' : '';
		echo '<div class="siteseo-step-page '.esc_attr($is_active).'" data-step="advanced">
		<span>Step '.esc_html(self::$current_step_no).' of '.count(self::$steps).'</span>
		<h1>Advanced Options</h1>
		<p>'.esc_html__('We\'re nearly there—just a few final optimizations left!', 'siteseo').'</p>
		<form method="POST">
			<div class="siteseo-input-block">
				<div class="siteseo-radiogroup">
					<label><input type="checkbox" name="universal_metabox" checked/>Enable Universal Metabox</label>
				</div>
				<p class="siteseo-input-description">'.esc_html__('Universal metabox makes SiteSEO on page content SEO helper compatible with every Page Builder, so if you are not using Gutenberg then this is a must.', 'siteseo').'</p>
			</div>
			<div class="siteseo-input-block">
				<div class="siteseo-radiogroup">
					<label><input type="checkbox" name="author_noindex"/>'.esc_html__('Don\'t let search engines index author archive pages', 'siteseo').'</label>
				</div>
				<p class="siteseo-input-description">'.esc_html__('Recommended: Enable this option if you are the sole author of the site to prevent duplicate content on author archive pages.', 'siteseo').'</p>
			</div>
			<div class="siteseo-input-block">
				<div class="siteseo-radiogroup">
					<label><input type="checkbox" name="redirect_attachment"/>'.esc_html__('Redirect attachment pages to the file itself', 'siteseo').'</label>
				</div>
				<p class="siteseo-input-description">'.esc_html__('By default SiteSEO redirects to the parent post.', 'siteseo').'</p>
			</div>
			<div class="siteseo-input-block">
				<div class="siteseo-radiogroup">
					<label><input type="checkbox" name="category_url"/>'.esc_html__('Remove /category/ in your permalinks', 'siteseo').'</label>
				</div>
				<p class="siteseo-input-description">'.esc_html__('This reduces the length of the URL.', 'siteseo').'</p>
			</div>';

			do_action('siteseo_gsc_onboarding');

			echo '<div class="siteseo-onboarding-content-footer">
				<button class="siteseo-skip-step siteseo-btn secondary">'.esc_html__('Skip Step', 'siteseo').'</button><button class="siteseo-btn primary siteseo-save-n-continue">'.esc_html__('Save and Continue', 'siteseo').'<span class="siteseo-spinner"></span></button>
			</div>
		</form>
		</div>';
	}
	
	static function ready_page(){
		$is_active = !empty(self::$current_step) && self::$current_step == 'ready' ? 'siteseo-step-active' : '';
		echo '<div class="siteseo-step-page '.esc_attr($is_active).'" data-step="ready">
		<span>Step '.esc_html(self::$current_step_no).' of '.count(self::$steps).'</span>
		<h1>Done! 🎉</h1>
		<p>'.esc_html__('We are done with the setup, now you can start making content and submit the Sitemap to the search engines.', 'siteseo').'</p>
		<h4>'.esc_html__('What Next?', 'siteseo').'</h4>
		<ol style="margin:0">
			<li><a href="?page=siteseo-sitemaps" target="_blank">'.esc_html__('Configure your Sitemap', 'siteseo').'</a></li>
			<li>'.esc_html__('Submit yours sitemap to search engines', 'siteseo').'</li>
		</ol>
		
		<h4>'.esc_html__('You can also, subscribe to our newletter', 'siteseo').'</h4>
		'.esc_html__('You will get', 'siteseo').'
		<ul style="list-style-type:none">
			<li><span class="dashicons dashicons-minus"></span> '.esc_html__('Alerted about Google Algorithm changes.', 'siteseo').'</li>
			<li><span class="dashicons dashicons-minus"></span> '.esc_html__('Updates about our products.', 'siteseo').'</li>
			<li><span class="dashicons dashicons-minus"></span> '.esc_html__('Improve SEO of your website with our resourceful blogs.', 'siteseo').'</li>
		</ul>
		<a class="siteseo-btn secondary" href="https://siteseo.io/subscribe/" style="align-self:flex-start;" target="_blank">'.esc_html__('Subscribe', 'siteseo').'</a>
		<div class="siteseo-onboarding-content-footer">
			<a href="'.esc_url(admin_url()).'"class="siteseo-btn primary">Go to Dashboard</a>
			<a href="?page=siteseo"class="siteseo-btn primary">Review Settings</a>
			<a href="https://siteseo.io/docs/" class="siteseo-btn primary" target="_blank">Knowledge Base</a>
		</div>
		</div>';
	}
}

settings/instant.php000064400000034275151526415240010615 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Instant{

	static function menu(){
		global $siteseo;

		$indexing_toggle = isset($siteseo->setting_enabled['toggle-instant-indexing']) ? $siteseo->setting_enabled['toggle-instant-indexing'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_siteseo_general';

		$instant_subtabs = [
			'tab_siteseo_general' => esc_html__('General', 'siteseo'),
			'tab_siteseo_settings' => esc_html__('Settings', 'siteseo'),
			'tab_siteseo_history' => esc_html__('History', 'siteseo'),
		];

		echo '<div id="siteseo-root">';
		Util::admin_header();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';
		wp_nonce_field('siteseo_instant_indexing');

		Util::render_toggle('Instant Indexing - SiteSEO', 'indexing_toggle', $indexing_toggle, $nonce);

		echo '<div id="siteseo-tabs" class="wrap">
		<div class="siteseo-nav-tab-wrapper">';

		foreach($instant_subtabs as $tab_key => $tab_caption){
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="'.esc_attr($tab_key).'-tab" class="siteseo-nav-tab'.esc_attr($active_class).'" data-tab="'.esc_attr($tab_key).'">'.esc_html($tab_caption).'</a>';
		}

		echo '</div>
		<div class"tab-content-wrapper">
		<div class="siteseo-tab'.($current_tab == 'tab_siteseo_general' ? ' active' : '').'" id="tab_siteseo_general" style="display: none;">';
		self::general();
		echo '</div>     
		<div class="siteseo-tab'.($current_tab == 'tab_siteseo_settings' ? ' active' : '').'" id="tab_siteseo_settings" style="display: none;">';
		self::settings();
		echo '</div>
		<div class="siteseo-tab'.($current_tab == 'tab_siteseo_history' ? 'active' : '').'" id="tab_siteseo_history" style="display : none;">';
		self::history();
		echo '</div>
		</div>';
		Util::submit_btn();
		echo '</form></div>';

	}

	static function general(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		$options = get_option('siteseo_instant_indexing_option_name');
		//$options = $siteseo->instant_settings;

		$option_engines = !empty($options['engines']) ? $options['engines'] : '';
		$option_search_engine_google = !empty($option_engines['google']) ? $option_engines['google'] : '';
		$option_search_engine_bing = !empty($option_engines['bing']) ? $option_engines['bing'] : '';
		$option_action = !empty($options['instant_indexing_google_action']) ? $options['instant_indexing_google_action'] : '';
		$option_manual_batch = !empty($options['instant_indexing_manual_batch']) ? $options['instant_indexing_manual_batch'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Instant Indexing','siteseo').'</h3>
		<div class="siteseo_wrap_label">
			<p class="description">'.esc_html__('Utilize the Indexing API to inform Google and Bing about updates or removals of pages from their indexes. The process may take a few minutes. You can submit URLs in batches of up to 100 (maximum 200 requests per day for Google).','siteseo').'</p>
		</div>

		<div class="siteseo-notice">
			<span class="dashicons dashicons-info"></span>
		    <div><h3>'.esc_html__('How does this work?', 'siteseo').'</h3>
			<ol>
			<li>'.
			/* translators: placeholders are just <strong> tag */ 
			wp_kses_post(sprintf(__('Setup your Google / Bing API keys from the %1$s Settings %2$s tab', 'siteseo'), '<strong>', '</strong>')).'</li>
			<li>'.
			/* translators: placeholders are just <strong> tag */ 
			wp_kses_post(sprintf(__('%1$s Enter the URLs %2$s you want to index in the field below.', 'siteseo'), '<strong>', '</strong>')).'</li>
				<li><strong>'.wp_kses_post(__('Save changes', 'siteseo')).'</strong></li>
			<li>'.
			/* translators: placeholders are just <strong> tag */ 
			wp_kses_post(sprintf(__('Click %1$s Submit URLs to Google & Bing  %2$s', 'siteseo'), '<strong>', '</strong>')).'</li>
			</ol>
			</div>
		</div>

		<table class="form-table">
		    <tbody>

		    	<tr>
				<th scope="row">'.esc_html__('select search engines','siteseo').'</th>
				<td> 
					<div class="siteseo_wrap_label"><label for="siteseo_search_engines">
						<input id="siteseo_search_engines" name="siteseo_options[search_engine_google]" type="checkbox"' . (!empty($option_search_engine_google) ? 'checked="yes"' : '') . ' value="1"/>'.esc_html__('Google', 'siteseo') . 
				            '</label></div>
					    <label for="siteseo_search_engines">
					    	<input id="siteseo_search_engines" name="siteseo_options[search_engine_bing]" type="checkbox"' . (!empty($option_search_engine_bing) ? 'checked="yes"' : '') . ' value="1"/>'.esc_html__('Bing', 'siteseo') . 
					    '</label>
				</td>
			</tr>

			<tr>
				<th scope="row">'.esc_html__('Which action to run for Google?', 'siteseo') .'</th>
				<td>
					<div class="siteseo_wrap_label">
						<label>
							<input id="siteseo_update_urls" name="siteseo_options[instant_indexing_actions]" type="radio" value="update_urls" '.checked($option_action, 'update_urls', false).'/>
							'.esc_html__('Update URLs', 'siteseo').'
						</label>
					</div>
					<div class="siteseo_wrap_label">
						<label>
							<input id="siteseo_remove_urls" name="siteseo_options[instant_indexing_actions]" type="radio" value="remove_urls" '.checked($option_action, 'remove_urls', false).'/>
							'.esc_html__('Remove URLs (the URL must return a 404 or 410 status code, or the page must include the <meta name="robots" content="noindex" /> meta tag).', 'siteseo').'
						</label>
					</div>
				</td>
			</tr>

			<tr>
				<th scope="row">'.esc_html__('Submit URLs for indexing','siteseo').'</th>
				<td>
					<textarea rows="20" name="siteseo_options[instant_indexing_batch]" placeholder="'.esc_html__('Submit one URL per line for search engine submission (maximum of 100 URLs).','siteseo').'">'.esc_attr($option_manual_batch).'</textarea>
				</td>
			</tr>

			<tr>
				<th scope="row"></th>
				<td>
					<button id="siteseo-submit-urls-button" class="btn btnSecondary">'.esc_html__('Submits URLs to Google & Bing', 'siteseo').'</button>
				</td><div style="position:absolute;margin-top:52.5%;margin-left:38%;" class="spinner"></div>
			</tr>
				
			<tr>
				<th scope="row"></th>
				<td>
					<div id="url-submitter-response"></div>
				</td>
			</tr>

		</tbody>
		</table><input type="hidden" name="siteseo_options[general]" value="1"/>';
	}

	static function settings(){
		global $siteseo,$docs;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		$docs['instant_indexing']['api'] = 'https://console.cloud.google.com/apis/library/indexing.googleapis.com?hl=en';
		$docs['instant_indexing']['google'] = 'https://siteseo.io/docs/api-cli-dev/use-google-instant-indexing-api-with-siteseo-pro/';

		//$options = $siteseo->instant_settings;
		$options = get_option('siteseo_instant_indexing_option_name');

		$option_google_api_key = !empty($options['instant_indexing_google_api_key']) ? $options['instant_indexing_google_api_key'] : '';
		$option_bing_api_key = !empty($options['instant_indexing_bing_api_key']) ? $options['instant_indexing_bing_api_key'] : '';
		$option_auto_url_submission = !empty($options['instant_indexing_automate_submission']) ? $options['instant_indexing_automate_submission'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Settings','siteseo').'</h3>
		<table class="form-table">
		<tbody>
		<tr>
		    <th scope="row">'.esc_html__('Instant Indexing Google API Key','siteseo').'</th>
		    <td>    
		        <textarea name="siteseo_options[google_api_key]" rows="12" placeholder="'.esc_html__('Paste your Google Json key file here','siteseo').'">'.esc_html($option_google_api_key).'</textarea>
		    </td>
		</tr>

		<tr>
			<th scope="row">'.esc_html__('Instant Indexing Bing API Key', 'siteseo').'</th>
			<td>
				<input type="text" id="bing-api-key" name="siteseo_options[bing_api_key]" placeholder="'.esc_html__('Enter your Bing Instant Indexing API', 'siteseo').'" value="'.esc_attr($option_bing_api_key).'">
				<button type="button" id="siteseo-generate-api-key-btn" class="btn btnSecondary">'.esc_html__('Generate key', 'siteseo').'</button>
				<p class="description">'.esc_html__('The Bing Indexing API key is generated automatically. Click Generate Key if you need to recreate it or if it missing.', 'siteseo') .'</p>
				<p class="description">'.esc_html__('A key should look like this: YjI4MGQxZmU0NWM1NGY2ZGIxMDk5M2VlYTAxMTUyODI=', 'siteseo') .'</p>
			</td>
		</tr>

		<tr>
		    <th scope="row">'.esc_html__('Automate URL Submission','siteseo').'</th>
		    <td> 
		        <label for="siteseo_search_engines">
		            <input id="siteseo_search_engines" name="siteseo_options[auto_submission]" type="checkbox"'.(!empty($option_auto_url_submission) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Activate automatic URL submission for the IndexNow API.', 'siteseo') . 
		        '</label>
		        <div class="siteseo_wrap_label">
		            <p class="description">'.esc_html__('Inform search engines via the IndexNow protocol whenever a post is created, updated, or removed.','siteseo').'</p>
		        </div>
		    </td>
		</tr>

		</tbody>
		</table><input type="hidden" name="siteseo_options[setting_tab]" value="1"/>';
	}
	
	static function history(){
		global $siteseo;
		
		$options = get_option('siteseo_instant_indexing_option_name');
		$indexing_history = !empty($options['indexing_history']) ? $options['indexing_history'] : '';
		
		echo'<h3 class="siteseo-tabs">'.esc_html__('History', 'siteseo').'</h3>
		<div class="siteseo_wrap_label">
			<p class="description">'.esc_html__('Most Recent 10 Indexing API Requests.', 'siteseo').'</p>
		</div>
		
		<table class="wp-list-table widefat fixed striped siteseo-history-table">
			<thead><tr>
				<th>'.esc_html__('Time & Date', 'siteseo').'</th>
				<th>'.esc_html__('URLs', 'siteseo').'</th>
				<th>'.esc_html__('Google Response', 'siteseo').'</th>
				<th>'.esc_html__('Bing Response', 'siteseo').'</th>
			</tr></thead>
			<tbody>';
			
			if(empty($indexing_history)){
				echo'<tr>
					<td>'.esc_html__('No submissions yet.', 'siteseo').'</td>
				</tr></tbody></table><br/><br/>';
				
				return;
			}
			
			foreach($indexing_history as $history){
				echo'<tr>
					<td>'.esc_html(date_i18n('Y-m-d H:i:s', $history['time'])).'</td>
					<td>'.esc_html(implode(', ', $history['urls'])).'</td>
					<td>'.(isset($history['google_status_code']) ? esc_html($history['google_status_code']) : 'N/A') . (isset($history['source']) && $history['source'] === 'auto' ? esc_html(' ( Auto )') : '') .'</td>
					<td>'.(isset($history['bing_status_code']) ? esc_html($history['bing_status_code']) : 'N/A') . (isset($history['source']) && $history['source'] === 'auto' ? esc_html(' ( Auto )') : '') . 
					'</td>

				</tr>';
			}
			
			echo'</tr>
			</tbody></table><br/>
			
			<tr>
				<td>
					<button id="siteseo-clear-history" class="btn btnSecondary">'.esc_html__('Clean History', 'siteseo').'</button>
				</td>
			</tr><br/><br/>
			
			<a class="siteseo-show-details">'.esc_html__('Response code guide', 'siteseo').'<span class="dash-icon dashicons dashicons-arrow-down-alt2"></span></a>
			<div class="siteseo-response-code-table">
			<table class="wp-list-table widefat fixed striped siteseo-history-table">
				<thead>
					<tr>
					<th>'.esc_html__('Response Code', 'siteseo').'</th>
					<th>'.esc_html__('Response Message', 'siteseo').'</th>
					<th>'.esc_html__('Reason', 'siteseo').'</th>
					</tr>
				</thead>
				
				<tr>
					<td>'.esc_html__('200', 'siteseo').'</td>
					<td>'.esc_html__('Ok', 'siteseo').'</td>
					<td>'.esc_html__('URLs submitted successfully.', 'siteseo').'</td>
				</tr>
				
				<tr>
					<td>'.esc_html__('202', 'siteseo').'</td>
					<td>'.esc_html__('Accepted', 'siteseo').'</td>
					<td>'.esc_html__('URL received. IndexNow key validation pending.', 'siteseo').'</td>
				</tr>
				
				<tr>
					<td>'.esc_html__('400', 'siteseo').'</td>
					<td>'.esc_html__('Bad Request', 'siteseo').'</td>
					<td>'.esc_html__('Request Invalid format.', 'siteseo').'</td>
				</tr>
				
				<tr>
					<td>'.esc_html__('403', 'siteseo').'</td>
					<td>'.esc_html__('Forbidden', 'siteseo').'</td>
					<td>'.esc_html__('Key not valid.', 'siteseo').'</td>
				</tr>
				
				<tr>
					<td>'.esc_html__('422', 'siteseo').'</td>
					<td>'.esc_html__('Unprocessable Entity', 'siteseo').'</td>
					<td>'.esc_html__('URLs don\'t belong to the host.', 'siteseo').'</td>
				</tr>
				
				<tr>
					<td>'.esc_html__('429', 'siteseo').'</td>
					<td>'.esc_html__('Too Many Requests', 'siteseo').'</td>
					<td>'.esc_html__('Too Many Requests: Potential Spam.', 'siteseo').'</td>
				</tr>
				<tbody>
			</table></div><br/><br/>';
		
	}

	static function save_settings(){
		global $siteseo;

		check_admin_referer('siteseo_instant_indexing');

		if(!siteseo_user_can('manage_instant_indexing')|| !is_admin()){
			return;
		}

		$options = $siteseo->instant_settings;
		
		if(!is_array($options)){
			$options = [];
		}

		if(empty($_POST['siteseo_options'])){
			return;
		}

		if(isset($_POST['siteseo_options']['general'])){
			// general tab
			$options['engines']['bing'] = isset($_POST['siteseo_options']['search_engine_bing']);
			$options['engines']['google'] = isset($_POST['siteseo_options']['search_engine_google']);
			$options['instant_indexing_google_action'] = isset($_POST['siteseo_options']['instant_indexing_actions']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['instant_indexing_actions'])) : 'URL_UPDATED';
			$options['instant_indexing_manual_batch'] = isset($_POST['siteseo_options']['instant_indexing_batch']) ? sanitize_textarea_field(wp_unslash($_POST['siteseo_options']['instant_indexing_batch'])) : '';
		}

		if(isset($_POST['siteseo_options']['setting_tab'])){
			// setting tab
			$options['instant_indexing_google_api_key'] = isset($_POST['siteseo_options']['google_api_key']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['google_api_key'])) : '';
			$options['instant_indexing_bing_api_key'] = isset($_POST['siteseo_options']['bing_api_key']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['bing_api_key'])) : '';
			$options['instant_indexing_automate_submission'] = isset($_POST['siteseo_options']['auto_submission']);
		}

		update_option('siteseo_instant_indexing_option_name', $options);
	}
}
settings/sitemap.php000064400000047232151526415240010574 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Sitemap{

    static function menu(){
		global $siteseo;

		$sitemap_toggle = isset($siteseo->setting_enabled['toggle-xml-sitemap']) ? $siteseo->setting_enabled['toggle-xml-sitemap'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_sitemap_general'; // Default tab

		$titles_meta_subtabs = [
			'tab_sitemap_general' => esc_html__('Home', 'siteseo'),
			'tab_sitemap_post_types' => esc_html__('Post types', 'siteseo'),
			'tab_sitemap_taxonomy ' => esc_html__('Taxonomy', 'siteseo'),
			'tab_sitmap_html' => esc_html__('HTML Sitemap', 'siteseo')
		];
		
		echo '<div id="siteseo-root">';
		Util::admin_header();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';

		wp_nonce_field('siteseo_sitemap_settings');

		Util::render_toggle('Sitemaps - SiteSEO', 'sitemap_toggle', $sitemap_toggle, $nonce);

		echo '<div id="siteseo-tabs" class="wrap">
		<div class="siteseo-nav-tab-wrapper">';

		foreach($titles_meta_subtabs as $tab_key => $tab_caption){
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="' . esc_attr($tab_key) . '-tab" class="siteseo-nav-tab' . esc_attr($active_class) . '" data-tab="' . esc_attr($tab_key) . '">' . esc_html($tab_caption) . '</a>';
		}

		echo '</div>
		<div class="tab-content-wrapper">
		<div class="siteseo-tab' .($current_tab == 'tab_sitemap_general' ? ' active' : '').'" id="tab_sitemap_general" style="display: none;">';
		self::general_sitemaps();
		echo '</div>  
		<div class="siteseo-tab' .($current_tab == 'tab_sitemap_post_types' ? ' active' : '').'" id="tab_sitemap_post_types" style="display: none;">';
		self::post_types_sitemaps();
		echo '</div>
		<div class="siteseo-tab' .($current_tab == 'tab_sitemap_taxonomy' ? ' active' : '').'" id="tab_sitemap_taxonomy" style="display: none;">';
		self::taxonomy_sitemap();
		echo '</div>  
		<div class="siteseo-tab' .($current_tab == 'tab_sitmap_html' ? ' active' : '').'" id="tab_sitmap_html" style="display: none;">';
		self::html_sitemap();
		echo '</div>
		</div>';

		Util::submit_btn();
		echo '</form></div>';
	}

    static function general_sitemaps(){
        global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		//$options = $siteseo->sitemap_settings;
		$options = get_option('siteseo_xml_sitemap_option_name', []);

		$xml_sitemap = !empty($options['xml_sitemap_general_enable']) ? $options['xml_sitemap_general_enable'] : '';
		$img_sitemap = !empty($options['xml_sitemap_img_enable']) ? $options['xml_sitemap_img_enable'] : '';
		$author_sitemap = !empty($options['xml_sitemap_author_enable']) ? $options['xml_sitemap_author_enable'] : '';
		$html_sitemap = !empty($options['xml_sitemap_html_enable']) ? $options['xml_sitemap_html_enable'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('General','siteseo').'</h3>
		<p>'.esc_html__('Sitemaps are pages which help search engine, know your site better and makes it easier for them to index the pages.','siteseo').'</p>
		<p>'.esc_html__('Not having a sitemap does not mean search engines won\'t be able to crawl your website, but sitemaps make it easier for them to discover all the URLs which are needed to be indexed.','siteseo').'</p>
		 <div class="siteseo-styles pre"><pre><span class="dashicons dashicons-external"></span><a href="'.esc_url(get_option('home')).'/sitemaps.xml" target="_blank">' . esc_url(get_option('home')) . '/sitemaps.xml</a></pre></div>
	        <div class="siteseo-notice">
			<span id="siteseo-dash-icon" class="dashicons dashicons-info"></span>
	        	<p>'.
			/* translators: placeholders are just <strong> tag */ 
			wp_kses_post(sprintf(__('To view your sitemap, %1$s enable permalinks %2$s (other than the default one) and save the settings to flush them.', 'siteseo'), '<strong>', '</strong>')).'</p>
	        </div>

	        <table class="form-table">
	            <tbody>
	                <tr>
	                    <th scope="row">'.esc_html__('Enable XML Sitemap','siteseo').'</th>
	                    <td>
	                     <label><input id="siteseo_enable_sitemap" name="siteseo_options[enable_xml_sitemap]" type="checkbox" '.(!empty($xml_sitemap) ? 'checked' : '').' value="1"/>'. esc_html__('Enable XML Sitemap', 'siteseo').'</label>
	                    </td>
	                </tr>

	                <tr>
	                    <th scope="row">'.esc_html__('Enable Image Sitemap','siteseo').'</th>
	                    <td>
	                        <label><input id="siteseo_image_sitemap" name="siteseo_options[enable_img_sitemap]" type="checkbox" '.(!empty($img_sitemap) ? 'checked' : '').' value="1"/>'. esc_html__('Enable Image Sitemap for standard images, image galleries, featured images, and WooCommerce / Kkart product images.)', 'siteseo').'</label>
	                        <p class="description">'.esc_html__('Images in XML sitemaps are only visible from the source code.', 'siteseo').'</p>
	                    </td>
	                </tr>

	                <tr>
	                    <th scope="row">'.esc_html__('Enable Author Sitemap','siteseo').'</th>
	                    <td>
	                        <label><input id="siteseo_author_sitemap" name="siteseo_options[enable_author_sitemap]" type="checkbox" '.(!empty($author_sitemap) ? 'checked' : '').' value="1"/>' . esc_html__('Enable Author Sitemap', 'siteseo').'</label>
	                        <p class="description">'.esc_html__('Ensure that you enable the author archive from SEO, under the Titles & Metas section, in the Archives tab.','siteseo').'</p>
	                    </td>
	                </tr> 

	                  <tr>
	                    <th scope="row">'.esc_html__('Enable HTML Sitemap','siteseo').'</th>
	                    <td>
	                        <label><input id="siteseo_html_sitemap" name="siteseo_options[enable_html_sitemap]" type="checkbox" '.(!empty($html_sitemap) ? 'checked' : ''). ' value="1"/>' . esc_html__('Enable HTML Sitemap', 'siteseo').'</label>
	                    </td>
	                </tr> 
				</tbody>
	        </table>
		<input type="hidden" name="siteseo_options[general_sitemaps] value="1"/>';

    }

	static function post_types_sitemaps(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		//$options = $siteseo->sitemap_settings;
		$options = get_option('siteseo_xml_sitemap_option_name', []);
		
		$option_sitemap_posts = !empty($options['xml_sitemap_post_types_list']['post']['include']) ? $options['xml_sitemap_post_types_list']['post']['include'] : '';
		$option_sitemap_pages = !empty($options['xml_sitemap_post_types_list']['page']['include']) ? $options['xml_sitemap_post_types_list']['page']['include'] : '';
		$option_sitemap_media = !empty($options['xml_sitemap_post_types_list']['media']['include']) ? $options['xml_sitemap_post_types_list']['media']['include'] : '';

		$post_types = siteseo_post_types();

		echo '<h3 class="siteseo-tabs">'.esc_html__('Post Types', 'siteseo').'</h3>
			<p>'.esc_html__('Select Post Types to Include or Exclude', 'siteseo').'</p>
				<table class="form-table">
					<tbody>';

						foreach($post_types as $post_type){
							$post_type_name = $post_type->name;
							$post_type_label = $post_type->labels->singular_name;
							$option_sitemap_custom = !empty($options['xml_sitemap_post_types_list'][$post_type_name]['include']) ? 'checked="yes"' : '';

							echo '<tr>
									<th></th>
									<td>
										<label for="sitemap_post_types_'.esc_attr($post_type_name).'">
											<h4>'.esc_html($post_type_label).' <em>(['.esc_html($post_type_name).'])</em></h4>
											<input id="sitemap_post_types_'.esc_attr($post_type_name).'" name="siteseo_options[xml_sitemap_post_types_list]['.esc_attr($post_type_name).'][include]" type="checkbox" '.esc_attr($option_sitemap_custom).' value="1"/>
											'.esc_html__('Include', 'siteseo').'
										</label>
									</td>
								</tr>';
						}

					echo '</tbody>
				</table>
				<input type="hidden" name= siteseo_options[post_types_tab] value="1"/>';
	}

    static function taxonomy_sitemap(){
        global $siteseo;
		
        if(!empty($_POST['submit'])){
            self::save_settings();
        }
		
		//$options = $siteseo->sitemap_settings;
		$get_taxonomies = get_taxonomies(['public' => true, 'show_ui' => true], 'objects');
		$check_taxonomies = apply_filters('siteseo_sitemaps_tax', $get_taxonomies);
	
		$options = get_option('siteseo_xml_sitemap_option_name');
		$option_category = isset($options['xml_sitemap_taxonomies_list']['category']['include']) ? $options['xml_sitemap_taxonomies_list']['category']['include'] : '';
		$option_post_tags = isset($options['xml_sitemap_taxonomies_list']['post_tag']['include']) ? $options['xml_sitemap_taxonomies_list']['post_tag']['include'] : '';
		
		$get_taxonomies = get_taxonomies();
		$check_taxomies = apply_filters('siteseo_sitemaps_tax', $get_taxonomies);
		
		$excluded_taxonomies = ['post_format', 'category', 'post_tag'];

        echo '<h3 class="siteseo-tabs">'.esc_html__('Taxonomies', 'siteseo').'</h3>
			<p>'.esc_html__('Select Taxonomies to Include or Exclude', 'siteseo').'</p>
            <table class="form-table">
                <tr scope="row">
                    <th>'.esc_html__('Select to INCLUDE Taxonomies', 'siteseo').'</th>
					
					<td><br/><br/>
						<label for="sitemap_post_types_pages">
							<h4>'.esc_html__('Categories ', 'siteseo').' <em>[categories]</em></h4>
							<input id="sitemap_post_types_pages" name="siteseo_options[xml_sitemap_taxonomies_list][category][include]" type="checkbox" '.(!empty($option_category) ? 'checked' : 'value="1"').'/>
							'.esc_html__('Include', 'siteseo').'
						</label>	
					</td>
                </tr>
            
				<tr>
					<th></th>
					<td>
						<label for="sitemap_post_types_pages">
							<h4>'.esc_html__('Tags', 'siteseo').' <em>[post_tag]</em></h4>
							<input id="sitemap_post_types_pages" name="siteseo_options[xml_sitemap_taxonomies_list][post_tag][include]" type="checkbox" '.(!empty($option_post_tags) ? 'checked' : 'value="1"').'/>
							'.esc_html__('Include', 'siteseo').'
						</label>
					</td>
				</tr>';
				
				foreach($check_taxonomies as $taxonomy_name => $taxonomy_obj){

					if(in_array($taxonomy_name, $excluded_taxonomies)){
						continue;
					}

					//check selected
					$is_included = !empty($options['xml_sitemap_taxonomies_list'][$taxonomy_name]['include']);

					// Generate a row for the taxonomy
					echo '<tr scope="row">
							<th></th>
							<td>
								<label for="sitemap_taxonomy_'.esc_attr($taxonomy_name).'">
									<h4>'.esc_html($taxonomy_obj->labels->name).' <em>[' . esc_html($taxonomy_name).']</em></h4>
									<input id="sitemap_taxonomy_' . esc_attr($taxonomy_name) . '" 
										   name="siteseo_options[xml_sitemap_taxonomies_list][' . esc_attr($taxonomy_name).'][include]" 
										   type="checkbox" '.($is_included ? 'checked' : '').' value="1" />
									' . esc_html__('Include', 'siteseo') . '
								</label>
							</td>
						  </tr>';
				}

            echo '</table><input type="hidden" name="siteseo_options[taxonomy_sitemap_tabs]" value="1">';

    }

    static function html_sitemap(){

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

	//$options = $siteseo->$sitemap_settings;
	$options = get_option('siteseo_xml_sitemap_option_name', []);
		
	$include_pages = !empty($options['xml_sitemap_html_mapping']) ? $options['xml_sitemap_html_mapping'] : '';
	$exclude_page = !empty($options['xml_sitemap_html_exclude']) ? $options['xml_sitemap_html_exclude'] : '';
	$order = !empty($options['xml_sitemap_html_order']) ? $options['xml_sitemap_html_order'] : '';
	$order_by = !empty($options['xml_sitemap_html_orderby']) ? $options['xml_sitemap_html_orderby'] : '';
	$disable_date = !empty($options['xml_sitemap_html_date']) ? $options['xml_sitemap_html_date'] : '';
	$remove_archive = !empty($options['xml_sitemap_html_archive_links']) ? $options['xml_sitemap_html_archive_links'] : '';
		

        echo '<h3 class="siteseo-tabs">'.esc_html__('HTML Sitemap', 'siteseo').'</h3>
        <p>'.esc_html__('Generate an HTML sitemap for your visitors to improve your SEO.','siteseo').'</p>
        <p>'.esc_html__('Restricted to 1,000 posts per post type. You can change the order and sorting settings below.','siteseo').'</p>

        <div class="siteseo-notice"><span class="dashicons dashicons-info"></span>
        <div>
            <h3>'.esc_html__('How to make use of the HTML Sitemap?', 'siteseo').'</h3>
            <h4>'.esc_html__('Block Editor', 'siteseo').'</h4>
		<p>'.
		/* translators: placeholders are just <strong> tag */ 
		wp_kses_post(sprintf(__('Insert the HTML sitemap block via the %1$s Block Editor %2$s.', 'siteseo'), '<strong>', '</strong>')).'</p>
            <h4>'.esc_html__('Shortcode', 'siteseo').'</h4>
            <p>'.esc_html__('You can also insert this shortcode into your content (post, page, custom post type, etc.):', 'siteseo').'</p>
            <div class="siteseo-styles pre"><pre>'.esc_attr('[siteseo_html_sitemap]').'</div></pre>
            <p>'.esc_html__('To include specific custom post types, use the CPT attribute:', 'siteseo') .'</p>
            <div class="siteseo-styles pre"><pre>'.esc_attr('[siteseo_html_sitemap cpt="post,product"]').'</div></pre>
            <h4>'.esc_html__('Other', 'siteseo').'</h4>
            <p>'.esc_html__('Display the sitemap dynamically by entering an ID in the first field below.', 'siteseo').'</p>
			</div>
		</div>
        
        <table class="form-table">
             <tr scope="row">
                <th>'.esc_html__('Post, Page, or Custom Post Type IDs to display:','siteseo').'</th>
                <td>
                    <input type="text" value="'.esc_html($include_pages).'" name="siteseo_options[page_numbers]" placeholder="'.esc_html__('eg:2, 28, 68','siteseo').'">
                </td>
            </tr>

            <tr scope="row">
                <th>'.esc_html__('Exclude Posts, Pages, Custom Post Types or Terms IDs:','siteseo').'</th>
                <td>
                    <input type="text" value="'.esc_html($exclude_page).'" name="siteseo_options[exclude_page]" placeholder="'.esc_html__('eg: 13 ,8 ,28','siteseo').'">
                </td>
            </tr>

            <tr scope="row">
                <th>'.esc_html__('Order:','siteseo').'</th>
                <td>
                    <select name="siteseo_options[order]">
                        <option value="DESC" '.selected($order, 'DESC', false).'>'.esc_html__('DESC (descending order from highest to lowest values (3, 2, 1; c, b, a))','siteseo').'</option>
                         <option value="ASC" '.selected($order, 'ASC', false).'>'.esc_html__('ASC (ascending order from lowest to highest values (1, 2, 3; a, b, c))','siteseo').'</option>
                    </select>
                </td>
            </tr>

            <tr scope="row">
                <th>'.esc_html__('Order By:','siteseo').'</th>
                <td>
                    <select name="siteseo_options[order_by]">
                        <option value="date" '.selected($order_by, 'date', false).'>'.esc_html__('Deafult (date)','siteseo').'</option>
                        <option value="post_title" '.selected($order_by, 'post_title', false).'>'.esc_html__('Post Title','siteseo').'</option>
                        <option value="modified_date" '.selected($order_by, 'modified_date', false).'>'.esc_html__('Modified date','siteseo').'</option>
                        <option value="post_id" '.selected($order_by, 'post_id', false).'>'.esc_html__('POST ID','siteseo').'</option>
                        <option value="menu_order" '.selected($order_by, 'menu_order', false).'>'.esc_html__('Menu Order','siteseo').'</option>
                    </select>
                </td>
            </tr>
            <tr scope="row">
                <th>'.esc_html__('Disable Date:','siteseo').'</th>
                <td>
                    <label for="sitemap_html_date">
                        <input id="sitemap_html_date" name="siteseo_options[disable_date]" type="checkbox" '.(!empty($disable_date) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Disable the date display after each post, page, or post type?', 'siteseo'). 
                    '</label>
                </td>
            </tr>

            <tr scope="row">
                <th>'.esc_html__('Remove Archive Links:','siteseo').'</th>
                <td>
                    <label for="sitemap_remove_link">
                        <input id="sitemap_remove_link" name="siteseo_options[remove_links]" type="checkbox" '.(!empty($remove_archive) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove links from archive pages (e.g., Products).', 'siteseo'). 
                    '</label>
                </td>
            </tr>
        </table><input type="hidden" name="siteseo_options[html_sitemap]" value="1"/>';
    }

    static function save_settings(){
		global $siteseo;

		check_admin_referer('siteseo_sitemap_settings');

		if(!siteseo_user_can('manage_sitemap') || !is_admin()){
			return;
		}

		$options = [];

		if(empty($_POST['siteseo_options'])){
			return;
		}
		
		if(isset($_POST['siteseo_options']['general_sitemaps'])){
			$options['xml_sitemap_general_enable'] = isset($_POST['siteseo_options']['enable_xml_sitemap']);
			$options['xml_sitemap_img_enable'] = isset($_POST['siteseo_options']['enable_img_sitemap']);
			$options['xml_sitemap_author_enable'] = isset($_POST['siteseo_options']['enable_author_sitemap']);
			$options['xml_sitemap_html_enable'] = isset($_POST['siteseo_options']['enable_html_sitemap']);

			flush_rewrite_rules();
		}

		if(isset($_POST['siteseo_options']['html_sitemap'])){
			
			$options['xml_sitemap_html_mapping'] = isset($_POST['siteseo_options']['page_numbers']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['page_numbers'])) : '';
			$options['xml_sitemap_html_exclude'] = isset($_POST['siteseo_options']['exclude_page']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['exclude_page'])) : '';
			$options['xml_sitemap_html_order'] = isset($_POST['siteseo_options']['order'])? sanitize_text_field(wp_unslash($_POST['siteseo_options']['order'])) : '';
			$options['xml_sitemap_html_orderby'] = isset($_POST['siteseo_options']['order_by']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['order_by'])) : '';
			$options['xml_sitemap_html_date'] = isset($_POST['siteseo_options']['disable_date']);
			$options['xml_sitemap_html_archive_links'] = isset($_POST['siteseo_options']['remove_links']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['remove_links'])) : '';
		}

		// posts 
		if(isset($_POST['siteseo_options']['post_types_tab'])){
			if(isset($_POST['siteseo_options']['xml_sitemap_post_types_list'])){
				$xml_post_types = map_deep(wp_unslash($_POST['siteseo_options']['xml_sitemap_post_types_list']), 'sanitize_text_field');
				foreach($xml_post_types as $posttypes_key => $posttypes_value) {
					if(isset($posttypes_value['include'])) {
						$options['xml_sitemap_post_types_list'][$posttypes_key]['include'] = $posttypes_value['include'];
					}
				}
			}
		}

		// Taxonomies
		if(isset($_POST['siteseo_options']['taxonomy_sitemap_tabs'])){
			if(isset($_POST['siteseo_options']['xml_sitemap_taxonomies_list'])){
				$xml_tax_list = map_deep(wp_unslash($_POST['siteseo_options']['xml_sitemap_taxonomies_list']), 'sanitize_text_field');
				foreach($xml_tax_list as $taxonomy_key => $taxonomy_value){
						if(isset($taxonomy_value['include'])){
							$options['xml_sitemap_taxonomies_list'][$taxonomy_key]['include'] = $taxonomy_value['include'];
						}
				}
			}
		}

		update_option('siteseo_xml_sitemap_option_name',$options);
    }
}
settings/advanced.php000064400000140755151526415240010703 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Advanced{

	static function menu(){
		global $siteseo;

		$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_image_seo'; // Default tab

		$titles_meta_subtabs = [
			'tab_image_seo' => esc_html__('Image SEO', 'siteseo'),
			'tab_advanced' => esc_html__('Advanced', 'siteseo'),
			'tab_appearance' => esc_html__('Appearance', 'siteseo'),
			'tab_security' => esc_html__('Security', 'siteseo'),
			'tab_toc' => esc_html__('Table of content', 'siteseo')
		];
		
		
		echo '<div id="siteseo-root">';
		Util::admin_header();

		echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';

		wp_nonce_field('siteseo_advance_settings');

		$advanced_toggle = isset($siteseo->setting_enabled['toggle-advanced']) ? $siteseo->setting_enabled['toggle-advanced'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

		Util::render_toggle('Image SEO & Advanced Settings - SiteSEO', 'advanced_toggle', $advanced_toggle, $nonce);

		echo '<div id="siteseo-tabs" class="wrap">
			<div class="siteseo-nav-tab-wrapper">';

		foreach($titles_meta_subtabs as $tab_key => $tab_caption){

			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="' . esc_attr($tab_key) . '-tab" class="siteseo-nav-tab' . esc_attr($active_class) . '" data-tab="' . esc_attr($tab_key) . '">' . esc_html($tab_caption) . '</a>';
		}

		echo '</div>		
		<div class="tab-content-wrapper">
		<div class="siteseo-tab '.($current_tab == 'tab_image_seo' ? ' active' : '').'" id="tab_image_seo" style="display: none;">';
		self::image_seo();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_advanced' ? ' active' : '').'" id="tab_advanced" style="display: none;">';
		self::advanced();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_appearance' ? ' active' : '').'" id="tab_appearance" style="display: none;">';
		self::appearance();
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_security' ? ' active' : '').'" id="tab_security" style="display: none;">';
		self::security(); 
		echo '</div>
		<div class="siteseo-tab '.($current_tab == 'tab_toc' ? ' active' : '').'" id="tab_toc" style="display: none;">';
		self::toc(); 
		echo '</div>
		</div>';

		Util::submit_btn();
		echo '</form></div>';

	}

	static function image_seo(){
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		//$options = $siteseo->$advanced_settings;
		$options = get_option('siteseo_advanced_option_name');

		$option_attachment = isset($options['advanced_attachments']) ? $options['advanced_attachments'] : '';
		$option_attachment_file = isset($options['advanced_attachments_file']) ? $options['advanced_attachments_file'] : '';
		$option_clean_filename = isset($options['advanced_clean_filename']) ? $options['advanced_clean_filename'] : '';
		$option_img_title = isset($options['advanced_image_auto_title_editor']) ? $options['advanced_image_auto_title_editor'] : '';
		$option_img_alt = isset($options['advanced_image_auto_alt_editor']) ? $options['advanced_image_auto_alt_editor'] : '';
		$option_target_key = isset($options['advanced_image_auto_alt_target_kw']) ? $options['advanced_image_auto_alt_target_kw'] : '';
		$option_cap_img = isset($options['advanced_image_auto_caption_editor']) ? $options['advanced_image_auto_caption_editor'] : '';
		$option_desc_img = isset($options['advanced_image_auto_desc_editor']) ? $options['advanced_image_auto_desc_editor'] : '';

		echo '<h3 class="siteseo-tabs">'.esc_html__('Image SEO','siteseo').'</h3>
        <p>'.esc_html__('Images can drive significant traffic to your site. Be sure to always add alt text, optimize file sizes, and properly name the files, among other best practices.','siteseo').'</p>

        <table class="form-table">
            <tbody class="siteseo_tbody">
                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Redirect attachment pages to the post parent page.','siteseo').'</th>
                    <td>
                        <label>
				        <input name="siteseo_options[attachment]" type="checkbox"'.(!empty($option_attachment) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Redirect attachment pages to the post parent, or to the homepage if no parent exists.', 'siteseo'). 
			            '</label>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Redirect attachment pages to their file URL','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[attachment_file]" type="checkbox"'.(!empty($option_attachment_file) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Redirect attachment pages to their respective file URLs (e.g., https://www.example.com/my-image-file.jpg).', 'siteseo'). 
                        '</label>
                        <p class="description">'.esc_html__('If this option is enabled, it will override the redirection of attachment pages to the post parent.','siteseo').'</p>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Cleaning media filename','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[clean_filename]" type="checkbox"'.(!empty($option_clean_filename) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('When uploading media, remove accents, spaces, and capital letters, and enforce UTF-8 encoding.', 'siteseo'). 
                        '</label>
                        <p class="description">'.esc_html__('e.g. "ExãMple 1 cópy!.jpg" => "example-1-copy.jpg"','siteseo').'</p>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Automatically set the image Title','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[auto_img_title]" type="checkbox"'.(!empty($option_img_title) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('When uploading an image file, automatically set the title to match the filename.', 'siteseo'). 
                        '</label>
                        <p class="description">' . esc_html__('We use the product title for ', 'siteseo') . esc_html(!defined('SITEPAD') ? 'WooCommerce' : 'Kkart') . esc_html__(' items.', 'siteseo') . '</p>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Automatically set the image Alt txt','siteseo').'</th>
                    <td>
                        <label><input name="siteseo_options[auto_img_alt]" type="checkbox"'.(!empty($option_img_alt) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('When uploading an image file, automatically set the alt text to match the filename.', 'siteseo'). 
                        '</label>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Automatically set the image alt text using target keywords..','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[auto_target_keyword]" type="checkbox"'.(!empty($option_target_key) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Use the target keywords if no alt text is set for the image.', 'siteseo'). 
                        '</label>
                        <p class="description">'.esc_html__('This setting will apply only to images without alt text on the frontend. It is retroactive, meaning if you disable it, images that previously had empty alt text will revert to being empty.','siteseo').'</p>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Automatically set the image Caption','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[caption_image]" type="checkbox"'.(!empty($option_cap_img) ? 'checked="yes"' : '') . ' value="1"/>'.esc_html__('When uploading an image file, automatically set the caption to match the filename.', 'siteseo') . 
                        '</label>
                    </td>
                <tr>

				<tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Automatically set the image Description','siteseo').'</th>
                    <td>
                        <label>
                            <input name="siteseo_options[description_img]" type="checkbox"'.(!empty($option_desc_img) ? 'checked="yes"' : ''). ' value="1"/>'.esc_html__('When uploading an image file, automatically set the description to match the filename.', 'siteseo'). 
                        '</label>
                    </td>
                <tr>

			</tbody>
		</table><input type="hidden" name="siteseo_options[image_seo]" value="1"/>';
	}
	
	static function advanced(){
		global $siteseo, $wp_version;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		//$options = $siteseo->advanced_settings;
		$options = get_option('siteseo_advanced_option_name');
		
		$platform_name = defined('SITEPAD') ? 'SitePad' : 'WordPress';

		$option_taxonomy_desc = isset($options['advanced_tax_desc_editor']) ? $options['advanced_tax_desc_editor'] : '';
		$option_category_url = isset($options['advanced_category_url']) ? $options['advanced_category_url'] : '';
		$option_noreferrer_link = isset($options['advanced_noreferrer']) ? $options['advanced_noreferrer'] : '';
		$option_wp_generator = isset($options['advanced_wp_generator']) ? $options['advanced_wp_generator'] : '';
		$option_hentry_post = isset($options['advanced_hentry']) ? $options['advanced_hentry'] : '';
		$option_author_url = isset($options['advanced_comments_author_url']) ? $options['advanced_comments_author_url'] : '';
		$option_site_fileds = isset($options['advanced_comments_website']) ? $options['advanced_comments_website'] : '';
		$option_rel_attributes = isset($options['advanced_comments_form_link']) ? $options['advanced_comments_form_link'] : '';
		$option_shortlink = isset($options['advanced_wp_shortlink']) ? $options['advanced_wp_shortlink'] : '';
		$option_wlw_meta_tag = isset($options['advanced_wp_wlw']) ? $options['advanced_wp_wlw'] : '';
		$option_rsd_meta_tag = isset($options['advanced_wp_rsd']) ? $options['advanced_wp_rsd'] : '';
		$option_google_meta_value = isset($options['advanced_google']) ? $options['advanced_google'] : '';
		$option_bing_meta_value = isset($options['advanced_bing']) ? $options['advanced_bing'] : '';
		$option_pinterest_meta_value = isset($options['advanced_pinterest']) ? $options['advanced_pinterest'] : '';
		$option_yandex_meta_value = isset($options['advanced_yandex']) ? $options['advanced_yandex'] : '';
		$option_remove_wocommerce_cat_url = isset($options['advanced_product_cat_url']) ? $options['advanced_product_cat_url'] : '';
		
		echo '<h3 class="siteseo-tabs">'.esc_html__('Advanced','siteseo').'</h3>
		<p class="description">'.esc_html__('Advanced SEO options for advanced users.','siteseo').'</p>
		<table class="form-table"/>
			<tbody>
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Add WP Editor to taxonomy description textarea','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[taxonomy_desc]" type="checkbox"'.(!empty($option_taxonomy_desc) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Add the TINYMCE editor to the term description field to enable rich text formatting.', 'siteseo'). 
			            '</label>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove /category/ in URL','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[category_url]" type="checkbox"'.(!empty($option_category_url) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove /category/ in your permalinks', 'siteseo'). 
			            '</label>
						<p class="description">'.esc_html('e.g. "https://example.com/category/my-post-category/" => "https://example.com/my-post-category/"').'</p>
					</td>
				</tr>
				
				<tr>
					<th scope="row">'.esc_html__('Remove category base from product permalinks', 'siteseo').'</th>
					<td>
						<label>
							<input type="checkbox" name="siteseo_options[remove_cate_woocommerce]" '.(!empty($option_remove_wocommerce_cat_url) ? 'checked="yes"' : '').' value="1"/>
							'.
							/* translators: placeholders are just html tags */ 
							wp_kses_post(sprintf(__('Remove %1$s product-category %2$s in your permalinks', 'siteseo'), '<strong>','</strong>')).'
							</label>
						</div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove noreferrer link attribute in post content','siteseo').'</th>
					<td>
						<label>
				        <input name="siteseo_options[noreferrer_link]" type="checkbox"'.(!empty($option_noreferrer_link) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove the noreferrer link attribute from the source code.', 'siteseo'). 
			            '</label>
						<p class="description">'.esc_html__('Useful for affiliate links (eg: Amazon)','siteseo').'</p>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.
					// translators: %s is the platform name
					sprintf(esc_html__('Remove %s meta generator tag', 'siteseo'), esc_html( $platform_name )).'</th>
					<td>
						<label>
							<input name="siteseo_options[wp_generator_meta]" type="checkbox"'.(!empty($option_wp_generator) ? 'checked="yes"' : '').' value="1"/>'. // translators: %s is the platform name
							sprintf(esc_html__('Remove %s meta generator in source code', 'siteseo'), esc_html( $platform_name)). 
						'</label>
						<div class="siteseo-styles pre"><pre>'.esc_html('<meta name="generator" content="WordPress '.(!empty($wp_version) ? $wp_version : '6.8.2').'" />').'</pre></div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove hentry post class','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[hentry_post]" type="checkbox"' . (!empty($option_hentry_post) ? 'checked="yes"' : '') . ' value="1"/>' . esc_html__('Remove the `hentry` post class to prevent Google from treating it as structured data (schema)', 'siteseo') . 
						'</label>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove author URL','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[comments_author_url]" type="checkbox"'.(!empty($option_author_url) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove the comment author URL in comments if the website field is filled in the profile page.', 'siteseo'). 
						'</label>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove website field from comment form','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[website_filed]" type="checkbox"'.(!empty($option_site_fileds) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove the website field from the comment form to reduce spam.', 'siteseo'). 
						'</label>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Add the "nofollow", "noopener", and "noreferrer" rel attributes to the links in the comment form.','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[comment_form_link]" type="checkbox"'.(!empty($option_rel_attributes) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Prevent search engines from following or indexing the link to the comment form by adding a "noindex", "nofollow" directive.', 'siteseo'). 
						'</label>
						
						<div class="siteseo-styles pre"><pre>'.esc_url('https://www.example.com/my-blog-post/#respond').'</pre></div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.
						// translators: %s is the platform name
					    sprintf(esc_html__('Remove %s shortlink meta tag', 'siteseo'), esc_html( $platform_name)).
					'</th>
					<td>
						<label>
							<input name="siteseo_options[shortlink]" type="checkbox"'.(!empty($option_shortlink) ? 'checked="yes"' : '') .' value="1"/>'. // translators: %s is the platform name
							sprintf(esc_html__('Remove %s shortlink meta tag in source.', 'siteseo'), esc_html( $platform_name )).
						'</label>
						
						<div class="siteseo-styles pre"><pre>'.esc_html('<link rel="shortlink" href="https://www.example.com/"/>').'</pre></div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove Windows Live Writer meta tag','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[wlw_meta]" type="checkbox"'.(!empty($option_wlw_meta_tag) ? 'checked="yes"' : '').' value="1"/>'.esc_html__('Remove the Windows Live Writer meta tag from the source code.', 'siteseo') . 
						'</label>
						
						<div class="siteseo-styles pre"><pre>'.esc_html('<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://www.example.com/wp-includes/wlwmanifest.xml" />').'</pre></div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Remove RSD meta tag','siteseo').'</th>
					<td>
						<label>
							<input name="siteseo_options[rsd_meta]" type="checkbox"'.(!empty($option_rsd_meta_tag) ? 'checked="yes"' : ''). ' value="1"/>'. esc_html__('Remove the Really Simple Discovery (RSD) meta tag from the source code.', 'siteseo'). 
						'</label>
						<p class="description">'.
						// translators: %s is the platform name
						sprintf(esc_html__('The %s Site Health feature will display an HTTPS warning if you enable this option. However, this is a false positive.', 'siteseo'), esc_html($platform_name)).'</p>
						<div class="siteseo-styles pre"><pre>' . esc_html('<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://www.example.com/wp-includes/wlwmanifest.xml" />') . '</pre></div>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Google site verification','siteseo').'</th>
					<td>
						<input name="siteseo_options[google_meta_value]" type="text" placeholder="'.esc_html__('Enter Google meta value site verification','siteseo').'" value="'.esc_attr($option_google_meta_value).'"/>
						<p class="description">'.
						/* translators: placeholders are just <strong> tag */ 
						wp_kses_post(sprintf(__('If your site is already verified in %1$s Google Search Console %2$s, you can leave this field blank.', 'siteseo'), '<strong>', '</strong>')).'
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Bing site verification','siteseo').'</th>
					<td>
						<input name="siteseo_options[bing_meta_value]" type="text" placeholder="'.esc_html__('Enter Bing meta value site verification','siteseo').'" value="'.esc_attr($option_bing_meta_value).'"/>
						<p class="description">'.
						/* translators: placeholders are just <strong> tag */ 
						wp_kses_post(sprintf(__('If your site is already verified in %1$s Bing Webmaster Tools %2$s, you can leave this field blank.', 'siteseo'), '<strong>', '</strong>')).'</p>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Pinterest site verification','siteseo').'</th>
					<td>
						<input name="siteseo_options[pinterest_meta_value]" type="text" placeholder="'.esc_html__('Enter the Pinterest meta value for site verification.','siteseo').'" value="'.esc_attr($option_pinterest_meta_value).'"/>
					</td>
				</tr>
				
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Yandex site verification','siteseo').'</th>
					<td>
						<input name="siteseo_options[yandex_meta_value]" type="text" placeholder="'.esc_html__('Enter the Yandex meta value for site verification.','siteseo').'" value="'.esc_attr($option_yandex_meta_value).'"/>
					</td>
				</tr>
			</tbody>
		</table><input type="hidden" name="siteseo_options[advanced_tab]" value="1"/>';

	}

	static function appearance(){
		
		global $siteseo;

		if(!empty($_POST['submit'])){
			self::save_settings();
		}

		//$options = $siteseo->advanced_settings;
		$options = get_option('siteseo_advanced_option_name');

		$option_enable_universal_metabox = isset($options['appearance_universal_metabox']) ? $options['appearance_universal_metabox'] : '';
		$option_disable_universal_metabox = isset($options['appearance_universal_metabox_disable']) ? $options['appearance_universal_metabox_disable'] : '';
		$option_content_analysis_metabox = isset($options['appearance_ca_metaboxe']) ? $options['appearance_ca_metaboxe'] : '';
		$option_hide_genesis_metabox = isset($options['appearance_genesis_seo_metaboxe']) ? $options['appearance_genesis_seo_metaboxe'] : ''; 
		$option_structured_type_metabox = isset($options['appearance_advice_schema']) ? $options['appearance_advice_schema'] : '';
		$option_admin_bar = isset($options['appearance_adminbar']) ? $options['appearance_adminbar'] : '';
		$option_noindex_admin_bar = isset($options['appearance_adminbar_noindex']) ? $options['appearance_adminbar_noindex'] : '';
		$option_column_title = isset($options['appearance_title_col']) ? $options['appearance_title_col'] : '';
		$option_column_desc = isset($options['appearance_meta_desc_col']) ? $options['appearance_meta_desc_col'] : '';
		$option_column_redirect = isset($options['appearance_redirect_enable_col']) ? $options['appearance_redirect_enable_col'] : '';
		$option_column_post_type = isset($options['appearance_redirect_url_col']) ? $options['appearance_redirect_url_col'] : '';
		$option_column_canonical_post_ty = isset($options['appearance_canonical']) ? $options['appearance_canonical'] : '';
		$option_column_target_key = isset($options['appearance_target_kw_col']) ? $options['appearance_target_kw_col'] : '';
		$option_column_noindex = isset($options['appearance_noindex_col']) ? $options['appearance_noindex_col'] : '';
		$option_column_nofollow = isset($options['appearance_nofollow_col']) ? $options['appearance_nofollow_col'] : '';
		$option_column_words_no = isset($options['appearance_words_col']) ? $options['appearance_words_col'] : '';
		$option_column_score = isset($options['appearance_score_col']) ? $options['appearance_score_col'] : '';
		$option_misc_genesis_metabox = isset($options['appearance_genesis_seo_menu']) ? $options['appearance_genesis_seo_menu'] : '';

		$appearance_fields =[
			'metaboxes'=>'Metaboxes',
			'Columns' => 'Columns',
			'Misc' =>'Misc',
		];
		
		if(!defined('SITEPAD')){
			$appearance_fields['admin-bar'] = 'Admin bar';
		}
		
		echo '<table class="form-table">
				<tbody>
					<tr>
						<th scope="row">
						 <div class="siteseo-container">';
							$is_first = true;
							foreach($appearance_fields as $post_key => $post_val){
								$active_class = $is_first ? 'active' : '';
								echo '<a href="#'.esc_attr($post_key).'" class="'.esc_attr($active_class).'">'.esc_html($post_val).'</a>';
								$is_first = false;
							}
						echo '</div>
						</th>
						<td>
							<div>
								<h3>'.esc_html__('Appearance','siteseo').'</h3>
								<div class="siteseo_wrap_label">
									<p class="description">'.esc_html__('Customize the plugin to fit your needs','siteseo').'</p>
								</div>
								<span class="line"></span>
								<h3>'.esc_html__('Metaboxes','siteseo').'</h3>
								<p>'.esc_html__('Edit your SEO metadata directly from your favorite page builder.','siteseo').'</p>
								<table class="form-table" id="metaboxes">
									<tbody>';
									if(!defined('SITEPAD')){
										echo '<tr>
											<th scope="row">'.esc_html__('Universal Metabox (Gutenberg)','siteseo').'</th>
											<td>
												<label><input type="checkbox" name="siteseo_options[enable_universal_metabox]" '.(!empty($option_enable_universal_metabox) ? 'checked="yes"' : 'value="1"').' "/> ' . esc_html__('Enable the universal SEO metabox for the Block Editor (Gutenberg)', 'siteseo') . '<label>
											</td>
										</tr>';
									}
										echo '<tr>
											<th scope="row">'.esc_html__('Disable Universal Metabox','siteseo').'</th>
											<td>
												</label><input type="checkbox" name="siteseo_options[disable_universal_metabox]" '.(!empty($option_disable_universal_metabox) ? 'checked="yes"' : 'value="1"').' "/>'.esc_html__('Disable the universal SEO metabox','siteseo').'
											</td>
										</tr>
										
										<tr>
											<th scope="row">'.esc_html__('Remove Content Analysis Metabox','siteseo').'</th>
											<td>
												<label><input type="checkbox" '.(!empty($option_content_analysis_metabox) ? 'checked="yes"' : 'value="1"').'  name="siteseo_options[remove_content_analysis]"> '.esc_html__(' Remove Content Analysis Metabox','siteseo').'</label>
												<p class="description">'.esc_html__('By checking this option, we will no longer track the significant keywords','siteseo').'</p>
											</td>
										</tr>
										
										
										<tr>
											<th scope=row">'.esc_html__('Hide Genesis SEO Metabox','siteseo').'</th>
											<td>
												<label><input type="checkbox" '.(!empty($option_hide_genesis_metabox) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[genesis_metabox]"> '.esc_html__(' Remove Genesis SEO Metabox', 'siteseo').'</label>
											</td>
										</tr>
										
										<tr>
											<th scope="row">'.esc_html__('Hide advice in Structured Data Types metabox','siteseo').'</th>
											<td>
												<label><input type="checkbox" '.(!empty($option_structured_type_metabox) ? 'checked="yes"' : 'value="1"').'    name="siteseo_options[structured_data_types_metabox]">'.esc_html__(' Remove the advice if None schema selected', 'siteseo').'</label>
											</td>
										</tr>
									</tbody>
									</table>';
									
									if(!defined('SITEPAD')){
										echo'<div id="Admin-bar">
										<span class="line"></span>
										<h3>'.esc_html__('Admin bar','siteseo').'</h3>
										<p class="description">'.esc_html__('The admin bar appears on the top of your pages when logged in to your WP admin','siteseo').'</p>
										<table>
										<tbody>
											<tr>
												<th scope="row">'.esc_html__('SEO in admin bar','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_admin_bar) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[admin_bar]"> '.esc_html__('Remove SEO from Admin Bar in backend and frontend', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Noindex in admin bar','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_noindex_admin_bar) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[noindex_admin_bar]"> '.esc_html__('Remove noindex item from Admin Bar in backend and frontend', 'siteseo').'</label>
												</td>
											</tr>
											
										</tbody>
										</table>
										</div>';
									}
									
									echo'<div id="Columns">
									<span class="line"></span>
									<h3>'.esc_html__('Columns','siteseo').'</h3>
									<p>'.esc_html__('Customize the SEO columns displayed in the posts/pages list.','siteseo').'</p>
									<table>
										<tbody>
											<tr>
												<th scope="row">'.esc_html__('Show Title tag column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_title) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[title_post_types]"> '.esc_html__('Add title column', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show Meta description column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_desc) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[desc_post_types]"> '.esc_html__('Add meta description column','siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show Redirection Enable column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_redirect) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[redirect_post_types]"> '.esc_html__('Add redirection enable column', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show Redirect URL column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_post_type) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[redirect_url_post_types]"> '.esc_html__('Add redirection URL column', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show canonical URL column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_canonical_post_ty) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[url_column_post_types]"> '.esc_html__('Add canonical URL column', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show Target Keyword column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_target_key) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[keyword_column_post_types]"> '.esc_html__('Add target keyword column', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show noindex column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_noindex) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[noindex_column_post_types]"> '.esc_html__('Display noindex status', 'siteseo').'</label>
												</td>
											</tr>
											
											<tr>
												<th scope="row">'.esc_html__('Show nofollow column in post types','siteseo').'</th>
													<td>
														<label><input type="checkbox" '.(!empty($option_column_nofollow) ? 'checked="yes"' : 'value="1"').'    name="siteseo_options[nofollow_column_post_types]"> '.esc_html__('Display nofollow status', 'siteseo').'</label>
													</td>
											</tr>											
											
											<th scope="row">'.esc_html__('Show total number of words column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_words_no) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[words_column_post_types]"> '.esc_html__('Display total number of words in content', 'siteseo').'</label>
												</td>
											</tr>
											
											<th scope="row">'.esc_html__('Show content analysis score column in post types','siteseo').'</th>
												<td>
													<label><input type="checkbox" '.(!empty($option_column_score) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[score_column_post_types]"> '.esc_html__('Display Content Analysis results column ("Good" or "Should be improved")', 'siteseo').'</label>
												</td>
											</tr>
											
										</tbody>
									</table>
									</div>
									<div id="Misc">
										<span class="line"></span>
										<h3>'.esc_html__('Misc','siteseo').'</h3>
										<div class="siteseo_wrap_label"><p>'.esc_html__('Miscellaneous settings for the SEO plugin.','siteseo').'</p></div>
										<table class="form-table">
											<tbody>
												<tr>
													<th scope="row">'.esc_html__('Hide Genesis SEO Settings link','siteseo').'</th>
													<td>
														<label><input type="checkbox" '.(!empty($option_misc_genesis_metabox) ? 'checked="yes"' : 'value="1"').' name="siteseo_options[genesis_seo_settings]">'.esc_html__('Remove Genesis SEO link in WP Admin Menu', 'siteseo') .'</label>
													</td>
												</tr>
											</tbody>
										</table>
									</div>
							</div>
						</td>
					</tr>
				</tbody>
			</table>
			<input type="hidden" name="siteseo_options[appearance_tab]"  value="1"/>';
	}
	
	static function security(){
		global $siteseo, $wp_roles, $submenu;
		
		if(!current_user_can('administrator')){
			echo '<div class="siteseo_wrap_label">
				<div class="siteseo-notice is-warning">
					<span id="dashicons-warning" class="dashicons dashicons-info"></span>&nbsp;
					<p>Only Admin can change security settings</p>
				</div>
			</div>';
			return;
		}

		if(!empty($_POST['submit'])){
			self::save_settings();
		}
		
		$options = get_option('siteseo_advanced_option_name');
		$menus_check = $submenu['siteseo'];
		$security_fields = [
			'siteseo-metaboxes' => 'SiteSEO Metaboxes',
			'siteseo-settings-pages' => 'SiteSEO setting pages',
		];
		
		$roles = get_editable_roles();

		if(empty($roles)){
			return;
		}

		wp_nonce_field('siteseo_advance_settings');

		echo '<table class="form-table">
			<tbody>
				<tr>
					<th scope="row">
						<div class="siteseo-container">';
						$is_first = true;
						foreach($security_fields as $post_key => $post_val){
							$active_class = $is_first ? 'active' : '';
							echo '<a href="#' . esc_attr($post_key) . '" class="' . esc_attr($active_class) . '">' . esc_html($post_val) . '</a>';
							$is_first = false;
						}
						echo '</div>
					</th>
					<td>
						<div>
							<h3 class="siteseo-tabs">'.esc_html__('Security', 'siteseo').'</h3>
							<div class="siteseo_wrap_label">
								<p class="description">'.esc_html__('Control access to SEO settings and metaboxes by user roles.', 'siteseo').'</p>
							</div>
							
							<h3 class="siteseo-tabs">'.esc_html__('SiteSEO metaboxes', 'siteseo').'</h3>
							<div class="siteseo_wrap_label">
								<p>'.esc_html__('Check a user role to prevent it from editing a specific metabox.', 'siteseo').'</p>
							</div>
							
							<table class="form-table" id="siteseo-metaboxes">
								<tbody>
									<tr>
										<th scope="row">'.esc_html__('Block SEO metabox to user roles', 'siteseo').'</th>
										<td>';
										foreach($roles as $key => $role){
											if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts' , $role['capabilities'])){
												continue;
											}

											$checked = isset($options['security_metaboxe_role'][$key]) ? 'checked' : '';
											echo '<label>
												<input type="checkbox" name="siteseo_options[security_metaboxe_role]['.esc_attr($key).']" value="1" '.esc_attr($checked).'/>
												<strong>'.esc_html($role['name']).'</strong>
											</label><br/><br/>';
										}
										echo '</td>
									</tr>
									
									<tr>
										<th scope="row">'.esc_html__('Block Content analysis metabox to user roles', 'siteseo').'</th>
										<td>';
										foreach($roles as $key => $role){
											if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts' , $role['capabilities'])){
												continue;
											}

											$checked = isset($options['security_metaboxe_ca_role'][$key]) ? 'checked' : '';
										echo '<label>
											<input type="checkbox" name="siteseo_options[security_metaboxe_ca_role]['.esc_attr($key).']" value="1" '.esc_attr($checked).'/><strong>'.esc_html($role['name']).'</strong>
											</label><br/><br/>';
										}
										echo '</td>
									</tr>
								</tbody>
							</table>
							
							<span class="line"></span>
							
							<h3 class="siteseo-tabs">'.esc_html__('SiteSEO settings pages', 'siteseo').'</h3>
							<p class="description">'.esc_html__('Check a user role to allow it to edit a specific settings page', 'siteseo').'</p>
							
							<table class="form-table" id="siteseo-settings-pages">
								<tbody>';
								
								$settings_pages = [
									'titles' => esc_html__('Titles & Metas', 'siteseo'),
									'xml-sitemap' => esc_html__('Sitemaps', 'siteseo'),
									'social' => esc_html__('Social Networks', 'siteseo'),
									'google-analytics' => esc_html__('Analytics', 'siteseo'),
									'instant-indexing' => esc_html__('Instant Indexing', 'siteseo'),
									'advanced' => esc_html__('Advanced', 'siteseo'),
								];
								
								foreach($settings_pages as $page_key => $page_title){
									echo '<tr>
										<th scope="row">' . esc_html($page_title) . '</th>
										<td>';
										foreach($roles as $role_key => $role){
											if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts' , $role['capabilities']) || $role_key == 'administrator'){
												continue;
											}
											
											$checked = isset($options['siteseo_advanced_security_metaboxe_siteseo-' . $page_key][$role_key]) ? 'checked' : '';
											echo '<label>
												<input type="checkbox" name="siteseo_options[siteseo_advanced_security_metaboxe_siteseo-' . esc_attr($page_key) . '][' . esc_attr($role_key) . ']" value="1" ' . esc_attr($checked) . '/>
												<strong>' . esc_html($role['name']) . '</strong>
											</label><br/><br/>';
										}
										echo '</td>
									</tr>';
								}

								//Pro 
								if(is_plugin_active('siteseo-pro/siteseo.php') && !defined('SITEPAD')){
									echo '<tr>
										<th scope="row">' . esc_html__('Pro Features', 'siteseo') . '</th>
										<td>';
										foreach($roles as $key => $role){
											if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts' , $role['capabilities']) || $key == 'administrator'){
												continue;
											}
											
											$checked = isset($options['siteseo_advanced_security_page_pro'][$key]) ? 'checked' : '';
											echo '<label>
												<input type="checkbox" name="siteseo_options[siteseo_advanced_security_page_pro][' . esc_attr($key) . ']" value="1" ' . esc_attr($checked) . '/>
												<strong>'.esc_html($role['name']).'</strong>
											</label><br/><br/>';
										}
										echo '</td>
									</tr>';
								}

								echo '</tbody>
							</table>
						</div>
					</td>
				</tr>
			</tbody></table><input type="hidden" name="siteseo_options[security_tab]" value="1"/>';
	}
	
	static function toc(){
		global $siteseo;
		
		if(!empty($_POST['submit'])){
			self::save_settings();
		}
		
		$options = get_option('siteseo_advanced_option_name');

		$option_toc_enable = isset($options['toc_enable']) ? $options['toc_enable'] : '';
		$option_toc_label = isset($options['toc_label']) ? $options['toc_label'] : '';
		$option_headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
		$option_list_types = [
			'ol' => __('Ordered List', 'siteseo'),
			'ul' => __('Unordered List', 'siteseo')
		];

		echo'<h3 class="siteseo-tabs">'.esc_html__('Table of Contents', 'siteseo').'</h3>
		<p>'.esc_html__('A table of content works as an index section for your post or page. It helps search engines understand your page structure and users find specific sections quickly, which might help SEO, as it helps search engines better understand the structure of your content and also improves user experience.', 'siteseo').'</p>
		<p>'.esc_html__('To use Table of Content on your pages, you can use this shortcode', 'siteseo').' <code>[siteseo_toc]</code></p>

		<table class="form-table">
			<tr>
				<th scope="row">'.esc_html__('Enable TOC', 'siteseo').'</th>
				<td>
					<label>
						<input type="checkbox" value="1" id="siteseo_toc_enable" name="siteseo_options[toc_enable]" '.checked($option_toc_enable, true, false).'/>
					</label>
				</td>
			</tr>
			<tr>
				<th scope="row">'.esc_html__('TOC Label', 'siteseo').'</th>
				<td>
					<label>
						<input type="text" value="'.esc_attr($option_toc_label).'" name="siteseo_options[toc_label]" placeholder="'.esc_attr__('Table of content', 'siteseo').'"/>
					</label>
				</td>
			</tr>
			<tr>
				<th scope="row">'.esc_html__('Exclude Headings', 'siteseo').'</th>
				<td>
					<div style="display:flex; gap: 20px;">';
					foreach($option_headings as $heading){
						$checked = !empty($options) && !empty($options['toc_excluded_headings']) && is_array($options['toc_excluded_headings']) && in_array($heading, $options['toc_excluded_headings']);
						echo '<label>
							<input type="checkbox" value="'.esc_attr($heading).'" name="siteseo_options[toc_excluded_headings][]" '.checked($checked, true, false).'/>'.esc_html(strtoupper($heading)).'
						</label>';
					}
					echo '</div>
				</td>
			</tr>
			<tr>
				<th scope="row">'.esc_html__('List Type', 'siteseo').'</th>
				<td>
					<div>
						<label>
							<select name="siteseo_options[toc_heading_type]">';
								foreach($option_list_types as $list_type => $list_title){
									$selected = !empty($options['toc_heading_type']) && $options['toc_heading_type'] == $list_type ? 'selected' : '';
									echo '<option value="'.esc_attr($list_type).'" '.esc_attr($selected).'>'.esc_html($list_title).'</option>';
								}
							echo '</select>
						</label>
					</div>
				</td>
			</tr>
		</table><input type="hidden" name="siteseo_options[toc_tab]" value="1" />';
	}

	static function save_settings(){
		global $siteseo;
		
		check_admin_referer('siteseo_advance_settings');
		
		if(!siteseo_user_can('manage_advanced') || !is_admin()){
			return;
		}
		
		$options = [];
		
		if(empty($_POST['siteseo_options'])){
			return;
		}
		
		if(isset($_POST['siteseo_options']['image_seo'])){
			$options['advanced_attachments'] = isset($_POST['siteseo_options']['attachment']);
			$options['advanced_attachments_file'] = isset($_POST['siteseo_options']['attachment_file']);
			$options['advanced_clean_filename'] = isset($_POST['siteseo_options']['clean_filename']);
			$options['advanced_image_auto_title_editor'] = isset($_POST['siteseo_options']['auto_img_title']);
			$options['advanced_image_auto_alt_editor'] = isset($_POST['siteseo_options']['auto_img_alt']);
			$options['advanced_image_auto_alt_target_kw'] = isset($_POST['siteseo_options']['auto_target_keyword']);
			$options['advanced_image_auto_caption_editor'] = isset($_POST['siteseo_options']['caption_image']);
			$options['advanced_image_auto_desc_editor'] = isset($_POST['siteseo_options']['description_img']);

		}
		
		if(isset($_POST['siteseo_options']['advanced_tab'])){
			
			$options['advanced_product_cat_url'] = isset($_POST['siteseo_options']['remove_cate_woocommerce']);
			$options['advanced_tax_desc_editor'] = isset($_POST['siteseo_options']['taxonomy_desc']);
			$options['advanced_category_url'] = isset($_POST['siteseo_options']['category_url']);
			$options['advanced_noreferrer'] = isset($_POST['siteseo_options']['noreferrer_link']);
			$options['advanced_wp_generator'] = isset($_POST['siteseo_options']['wp_generator_meta']);
			$options['advanced_hentry'] = isset($_POST['siteseo_options']['hentry_post']);
			$options['advanced_comments_author_url'] = isset($_POST['siteseo_options']['comments_author_url']);
			$options['advanced_comments_website'] = isset($_POST['siteseo_options']['website_filed']);
			$options['advanced_comments_form_link'] = isset($_POST['siteseo_options']['comment_form_link']);
			$options['advanced_wp_shortlink'] = isset($_POST['siteseo_options']['shortlink']);
			$options['advanced_wp_rsd'] = isset($_POST['siteseo_options']['rsd_meta']);
			$options['advanced_wp_wlw'] = isset($_POST['siteseo_options']['wlw_meta']);
			$options['advanced_google'] = isset($_POST['siteseo_options']['google_meta_value']) ? sanitize_text_field(Util::extract_content(wp_unslash($_POST['siteseo_options']['google_meta_value']))) : '';
			$options['advanced_bing'] = isset($_POST['siteseo_options']['bing_meta_value']) ? sanitize_text_field(Util::extract_content(wp_unslash($_POST['siteseo_options']['bing_meta_value']))) : '';
			$options['advanced_pinterest'] = isset($_POST['siteseo_options']['pinterest_meta_value']) ? sanitize_text_field(Util::extract_content(wp_unslash($_POST['siteseo_options']['pinterest_meta_value']))) : '';
			$options['advanced_yandex'] = isset($_POST['siteseo_options']['yandex_meta_value']) ? sanitize_text_field(Util::extract_content(wp_unslash($_POST['siteseo_options']['yandex_meta_value']))) : '';

		}
		
		if(isset($_POST['siteseo_options']['appearance_tab'])){
			
			$options['appearance_universal_metabox'] = isset($_POST['siteseo_options']['enable_universal_metabox']);
			$options['appearance_universal_metabox_disable'] = isset($_POST['siteseo_options']['disable_universal_metabox']);
			$options['appearance_ca_metaboxe'] = isset($_POST['siteseo_options']['remove_content_analysis']);
			$options['appearance_genesis_seo_metaboxe'] = isset($_POST['siteseo_options']['genesis_metabox']);
			$options['appearance_advice_schema'] = isset($_POST['siteseo_options']['structured_data_types_metabox']);
			$options['appearance_adminbar'] = isset($_POST['siteseo_options']['admin_bar']);
			$options['appearance_adminbar_noindex'] = isset($_POST['siteseo_options']['noindex_admin_bar']);
			$options['appearance_title_col'] = isset($_POST['siteseo_options']['title_post_types']);
			$options['appearance_meta_desc_col'] = isset($_POST['siteseo_options']['desc_post_types']);
			$options['appearance_redirect_enable_col'] = isset($_POST['siteseo_options']['redirect_post_types']);
			$options['appearance_redirect_url_col'] = isset($_POST['siteseo_options']['redirect_url_post_types']);
			$options['appearance_canonical'] = isset($_POST['siteseo_options']['url_column_post_types']);
			$options['appearance_target_kw_col'] = isset($_POST['siteseo_options']['keyword_column_post_types']);
			$options['appearance_noindex_col'] = isset($_POST['siteseo_options']['noindex_column_post_types']);
			$options['appearance_nofollow_col'] = isset($_POST['siteseo_options']['nofollow_column_post_types']);
			$options['appearance_words_col'] = isset($_POST['siteseo_options']['words_column_post_types']);
			$options['appearance_score_col'] = isset($_POST['siteseo_options']['score_column_post_types']);
			$options['appearance_genesis_seo_menu'] = isset($_POST['siteseo_options']['genesis_seo_settings']);
			
		}
		
		if(isset($_POST['siteseo_options']['toc_tab'])){

			$options['toc_enable'] = isset($_POST['siteseo_options']['toc_enable']);
			$options['toc_label'] = isset($_POST['siteseo_options']['toc_label']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['toc_label'])) : '';
			$options['toc_heading_type'] = isset($_POST['siteseo_options']['toc_heading_type']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['toc_heading_type'])) : '';

			//toc_excluded_headings
			if(isset($_POST['siteseo_options']['toc_excluded_headings'])){
				$options['toc_excluded_headings'] = map_deep(wp_unslash($_POST['siteseo_options']['toc_excluded_headings']), 'sanitize_text_field');
			}
			
		}
		
		
		if(isset($_POST['siteseo_options']['security_tab']) && current_user_can('manage_options')){
			
			$has_admin = ['security_metaboxe_role', 'security_metaboxe_ca_role'];
			
			$settings = [
				'security_metaboxe_role',
				'security_metaboxe_ca_role',
				'siteseo_advanced_security_metaboxe_siteseo-titles',
				'siteseo_advanced_security_metaboxe_siteseo-xml-sitemap',
				'siteseo_advanced_security_metaboxe_siteseo-social',
				'siteseo_advanced_security_metaboxe_siteseo-google-analytics',
				'siteseo_advanced_security_metaboxe_siteseo-instant-indexing',
				'siteseo_advanced_security_metaboxe_siteseo-advanced',
				'siteseo_advanced_security_metaboxe_siteseo-import-export'
			];

			$advanced_options = map_deep($_POST['siteseo_options'], function($value){
				
				if(!empty($value)){
					if(is_string($value)){
						return true;
					}

					return sanitize_text_field(wp_unslash($value));
				}

				return '';
			});
			
			$filtered_options = [];
			$roles = get_editable_roles();
			foreach($settings as $setting){
				$accepted_roles = [];
				foreach($roles as $key => $role){
					// We will skip, admin if the setting does not require it.
					if(!in_array($setting, $has_admin) && $key ==  'administrator'){
						continue;
					}
					
					// We only accept roles which has capability to 'publish_posts', as giving access to anyone less does not makes sense.
					if(empty($role['capabilities']) || !is_array($role['capabilities']) || !array_key_exists('publish_posts' , $role['capabilities'])){
						continue;
					}

					array_push($accepted_roles, $key);
				}
				
				// Making sure the roles being pushed are the once we want.
				if(isset($advanced_options[$setting])){
					$filtered_options[$setting] = array_intersect(
						$advanced_options[$setting],
						array_flip($accepted_roles)
					);
				}
			}

			$options = array_merge($options, $filtered_options);
		}

		update_option('siteseo_advanced_option_name', $options);
	}

}
settings/social.php000064400000063224151526415240010403 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Settings;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Social{

    static function menu(){
        global $siteseo;

		$social_toggle = isset($siteseo->setting_enabled['toggle-social']) ? $siteseo->setting_enabled['toggle-social'] : '';
		$nonce = wp_create_nonce('siteseo_toggle_nonce');

        $current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'tab_knowledge_graph';

        $social_subtabs = [
            'tab_knowledge_graph' => esc_html__('Knowledge Graph', 'siteseo'),
            'tab_social_accounts' => esc_html__('Your social accounts', 'siteseo'),
            'tab_facebook' => esc_html__('Facebook (Open Graph) ', 'siteseo'),
            'tab_twitter' => esc_html__('X Card', 'siteseo')
        ];
		
		echo '<div id="siteseo-root">';
		
		Util::admin_header();

        echo '<form method="post" id="siteseo-form" class="siteseo-option" name="siteseo-flush">';

        wp_nonce_field('siteseo_social_settings');

		Util::render_toggle('Social Networks - SiteSEO', 'social_toggle', $social_toggle, $nonce);

        echo '<div id="siteseo-tabs" class="wrap">
        <div class="siteseo-nav-tab-wrapper">';

        foreach($social_subtabs as $tab_key => $tab_caption){
			$active_class = ($current_tab === $tab_key) ? ' siteseo-nav-tab-active' : '';
			echo '<a id="' . esc_attr($tab_key) . '-tab" class="siteseo-nav-tab' . esc_attr($active_class) . '" data-tab="' . esc_attr($tab_key) . '">' . esc_html($tab_caption) . '</a>';
        }

        echo '</div>
		<div class="tab-content-wrapper">
        <div class="siteseo-tab' .($current_tab == 'tab_knowledge_graph' ? ' active' : '').'" id="tab_knowledge_graph" style="display: none;">';
        self::knowledge_graph();
        echo '</div>
        <div class="siteseo-tab' .($current_tab == 'tab_social_accounts' ? ' active' : '').'" id="tab_social_accounts" style="display: none;">';
        self::social_accouts();
        echo '</div>
        <div class="siteseo-tab' .($current_tab == 'tab_twitter' ? ' active' : '').'" id="tab_twitter" style="display: none;">';
        self::twitter();
        echo '</div>
        <div class="siteseo-tab' .($current_tab == 'tab_facebook' ? ' active' : '').'" id="tab_facebook" style="display: none;">';
        self::facebook();
        echo '</div>
		</div>'; 

        Util::submit_btn();
        echo '</form></div>';
 
    }

    static function knowledge_graph(){
        global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

        $options = get_option('siteseo_social_option_name');

        //load data
        $option_org_type = !empty($options['social_knowledge_type']) ? $options['social_knowledge_type'] : '';
        $option_org_name = !empty($options['social_knowledge_name']) ? $options['social_knowledge_name'] : '';
        $option_org_logo = !empty($options['social_knowledge_img']) ? $options['social_knowledge_img'] : '';
        $option_org_number = !empty($options['social_knowledge_phone']) ? $options['social_knowledge_phone'] : '';
        $option_org_contact_type = !empty($options['social_knowledge_contact_type']) ? $options['social_knowledge_contact_type'] : '';
        $option_org_contact_option = !empty($options['social_knowledge_contact_option']) ? $options['social_knowledge_contact_option'] : '';

        echo '<h3 class="siteseo-tabs">'.esc_html__('Knowledge Graph','siteseo').'</h3>
        <p class="description">'.esc_html__('Set up Google Knowledge Graph.','siteseo').'</p>
        <table class="form-table">
            <tbody>
                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Person or organization','siteseo').'</th>
                    <td>
                        <select name="siteseo_options[org_type]">
                            <option value="none" '.selected($option_org_type, 'none', false).'>'.esc_html__('None','siteseo').'</option>
                            <option value="Person" '.selected($option_org_type, 'Person', false).'>'.esc_html__('Person','siteseo').'</option>
                            <option value="Organization" '.selected($option_org_type, 'Organization', false).'>'.esc_html__('Organization','siteseo').'</option>
                        </select>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Your name/organization','siteseo').'</th>
                    <td>
                        <input type="text" name="siteseo_options[org_name]" value="'.esc_attr($option_org_name).'" placeholder="'.esc_html__('eg.Miremont','siteseo').'">
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Your photo/organization logo','siteseo').'</th>
                    <td>
                        <input id="knowledge_org_logo_url" autocomplete="off" type="text" name="siteseo_options[org_logo]" value="'.esc_url($option_org_logo).'" placeholder="'.esc_html__('select your logo','siteseo').'">
                        <button id="knowledge_org_logo" class="btn btnSecondary">'.esc_html__('Upload an image','siteseo').'</button>
 			<p class="description">'.esc_html__('JPG, PNG, WebP and GIF allowed.','siteseo').'</p><br />		
 			<img style="width:300px;max-height:400px;" src="'.esc_url($option_org_logo).'" />
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Organizations phone number (only for Organizations)','siteseo').'</th>
                    <td>
                        <input type="text" name="siteseo_options[org_contact_number]" value="'.esc_attr($option_org_number).'" placeholder="'.esc_html__('eg: +33123456789 (internationlized version required)','siteseo').'">
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Contact type (only for Organizations)','siteseo').'</th>
                    <td>
                        <select name="siteseo_options[org_contact_type]">
                            <option value="Customer support" '.selected($option_org_contact_type, 'Customer support', false).'>'.esc_html__('Customer support','siteseo').'</option>
                            <option value="Technical support" '.selected($option_org_contact_type, 'Technical support', false).'>'.esc_html__('Technical support','siteseo').'</option>
                            <option value="Billing support" '.selected($option_org_contact_type, 'Billing support', false).'>'.esc_html__('Billing support','siteseo').'</option>
                            <option value="Bill payment" '.selected($option_org_contact_type, 'Bill payment', false).'>'.esc_html__('Bill payment','siteseo').'</option>
                            <option value="Sales payment" '.selected($option_org_contact_type, 'Sales payment', false).'>'.esc_html__('Sales payment','siteseo').'</option>
                            <option value="Credit card support" '.selected($option_org_contact_type, 'Credit card support', false).'>'.esc_html__('Credit card support','siteseo').'</option>
                            <option value="Emergency support" '.selected($option_org_contact_type, 'Emergency support', false).'>'.esc_html__('Emergency support','siteseo').'</option>
                            <option value="Baggage tracking" '.selected($option_org_contact_type, 'Baggage tracking', false).'>'.esc_html__('Baggage tracking','siteseo').'</option>
                            <option value="Roadside assistance" '.selected($option_org_contact_type, 'Roadside assistance', false).'>'.esc_html__('Roadside assistance','siteseo').'</option>
                            <option value="Package tracking" '.selected($option_org_contact_type, 'Package tracking', false).'>'.esc_html__('Package tracking','siteseo').'</option>
                        </select>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Contact option (only for Organizations)','siteseo').'</th>
                    <td>
                        <select name="siteseo_options[org_contact_option]">
                            <option value="None" '.selected($option_org_contact_option, 'None', false).'>'.esc_html__('None','siteseo').'</option>
                            <option value="TollFree" '.selected($option_org_contact_option, 'TollFree', false).'>'.esc_html__('TollFree', 'siteseo').'</option>
                            <option value="HearingImpairedSupported" '.selected($option_org_contact_option, 'HearingImpairedSupported', false).'>'.esc_html__('Hearing Impaired Supported','siteseo').'</option>
                        </select>
                    </td>
                </tr>        
            </tbody>
        </table><input type="hidden" name="siteseo_options[knowledge_graph_tab]" value="1" >';
    }

    static function social_accouts(){
        global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		//$options = $siteseo->social_settings;
        $options = get_option('siteseo_social_option_name');

        //load settings
        $facebook_acct = !empty($options['social_accounts_facebook']) ? $options['social_accounts_facebook'] : '';
        $twitter_acct = !empty($options['social_accounts_twitter']) ? $options['social_accounts_twitter'] : '';
        $instagram_acct = !empty($options['social_accounts_instagram']) ? $options['social_accounts_instagram'] : '';
        $youtube_acct = !empty($options['social_accounts_youtube']) ? $options['social_accounts_youtube'] : '';
        $pinterest_acct = !empty($options['social_accounts_pinterest']) ? $options['social_accounts_pinterest'] : '';
        $additional_acct = !empty($options['social_accounts_additional']) ? implode("\n", $options['social_accounts_additional']) : '';

        echo '<h3 class="siteseo-tabs">'.esc_html__('Your social accouts', 'siteseo').'</h3>
         <table class="form-table">
            <tbody>
                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Facebook', 'siteseo').'</th>
                    <td>
                        <input type="text" name="siteseo_options[facebook]" placeholder="'.esc_html__('eg: https://facebook.com/my-page-url','siteseo').'" value="'.esc_url($facebook_acct).'">
                    </td>
                </tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('X Username', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[twitter]" placeholder="'.esc_html__('eg : x_username','siteseo').'" value="'.esc_attr($twitter_acct).'">
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Pinterest URL', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[pinterest]" placeholder="'.esc_html__('eg : https://pinterest.com/my-page-url/','siteseo').'" value="'.esc_url($pinterest_acct).'">
					</td>
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Instagram URL', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[instagram]" placeholder="'.esc_html__('eg : https://www.instagram.com/my-page-url/','siteseo').'" value="'.esc_url($instagram_acct).'">
					</td>   
				</tr>

				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('YouTube URL', 'siteseo').'</th>
					<td>
						<input type="text" name="siteseo_options[youtube]" placeholder="'.esc_html__('eg : https://www.youtube.com/my-channel-url/','siteseo').'" value="'.esc_url($youtube_acct).'">
					</td>   
				</tr>
				<tr>
					<th scope="row" style="user-select:auto;">'.esc_html__('Additional Accounts', 'siteseo').'</th>
					<td>
						<textarea name="siteseo_options[additional]" placeholder="'.esc_html__('eg : https://somesite.com/my-channel-url/','siteseo').'">'.esc_textarea($additional_acct).'</textarea>
						<p class="description">'.esc_html__('Enter 1 URL per line.', 'siteseo').'</p>
					</td>
				</tr>
 
            </tbody>
        </table><input type="hidden" name="siteseo_options[social_account_tab]" value="1">';
    }

    static function twitter(){
        global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

		//$options = $siteseo->social_settings;
        $options = get_option('siteseo_social_option_name');

        //load data
        $option_enable_card = !empty($options['social_twitter_card']) ? $options['social_twitter_card'] : '';
	$option_image_size = !empty($options['social_twitter_card_img_size']) ? $options['social_twitter_card_img_size'] : '';
	$option_twitter_img = !empty($options['social_twitter_card_img']) ? $options['social_twitter_card_img'] : '';

        echo '<h3 class="siteseo-tabs">'.esc_html__('X Card','siteseo').'</h3>
        <p class="description">'.esc_html__('Manage your X card','siteseo').'</p>

        <div class="siteseo-notice">
            <span class="dashicons dashicons-info"></span>
            <div>
                <p>'.
		/* translators: placeholders are just <strong> tag */ 
		wp_kses_post(sprintf(__('We generate the %1$s og:image %2$s meta in the following order:', 'siteseo'), '<strong>', '</strong>')).'</p>
                <ol>
                    <li>'.esc_html__('Custom OG Image from the SEO metabox', 'siteseo').'</li>
                    <li>'.esc_html__('Post thumbnail / Product category thumbnail (Featured image)', 'siteseo').'</li>
                    <li>'.esc_html__('First image of your post content', 'siteseo').'</li>
                    <li>'.esc_html__('Global OG Image set in SEO > Social > Open Graph', 'siteseo').'</li>
                    <li>'.esc_html__('Site icon from the Customizer', 'siteseo').'</li>
                </ol>
            </div>
        </div>
        
        <table class="form-table">
            <tbody>
                <tr>
                    <th scope="row" style="user:select-auto;">'.esc_html__('X Card','siteseo').'</th>
                    <td>'.esc_html__('Manage your X Card','siteseo').'</td>
                </tr>

                <tr>
                    <th scope="row" style="user:select-auto;">'.esc_html__('Enable X Card','siteseo').'</th>
                    <td>
                       <label for="enable_twitter_card"><input id="enable_twitter_card" type="checkbox" name="siteseo_options[enable_twitter_card]" '.(!empty($option_enable_card) ? 'checked="checked"' : 'value="1"') . '>'.esc_html__('Enable X card', 'siteseo') .'</label>
                    </td>
                </tr>
				
                <tr>
                    <th scope="row" style="user:select-auto;">'.esc_html__('Default X Image','siteseo').'</th>
                    <td>
                        <input type="text" id="twitter_logo_url" autocomplete="off" name="siteseo_options[twitter_img]" value="'.esc_url($option_twitter_img).'" placeholder="'.esc_html__('Choose your default thumbnail.','siteseo').'">
						<button id="twitter_logo" class="btn btnSecondary">'.esc_html__('Upload a image','siteseo').'</button>
						<p class="description">'.esc_html__('Minimum size: 144x144px (300x157px with large card), recommended aspect ratio 1:1 (2:1 for large card), maximum file size 5MB.','siteseo').'</p>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user:select-auto;">'.esc_html__('X Card Image Size','siteseo').'</th>
                    <td>
                        <select name="siteseo_options[image_size]">
                            <option value="Default" '.selected($option_image_size, 'Default', false).'>'.esc_html__('Default','siteseo').'</option>
                            <option value="Large" '.selected($option_image_size, 'Large', false).'>'.esc_html__('Large','siteseo').'</option>
                        </select>
                    </td>
                </tr>
				
            </tbody>
        </table><input type="hidden" name="siteseo_options[twitter_tab]" value="1">';
    }

    static function facebook(){
        global $siteseo;

        if(!empty($_POST['submit'])){
            self::save_settings();
        }

        // load seetings
		//$options = $siteseo->social_settings;
        $options = get_option('siteseo_social_option_name');

        $option_fb_enable_og = !empty($options['social_facebook_og']) ? $options['social_facebook_og'] : '';
        $option_fb_img = !empty($options['social_facebook_img']) ? $options['social_facebook_img'] : '';
        $option_fb_defult_img = !empty($options['social_facebook_img_default']) ? $options['social_facebook_img_default'] : '';
        $option_fb_ownership = !empty($options['social_facebook_link_ownership_id']) ? $options['social_facebook_link_ownership_id'] : '';
        $option_fb_admin_id = !empty($options['social_facebook_admin_id']) ? $options['social_facebook_admin_id'] : '';

        echo '<h3 class="siteseo-tabs">'.esc_html__('Facebook (Open Graph)','siteseo').'</h3>
        <p class="description">'.esc_html__('Manage Open Graph data to enhance how your links appear on platforms like Facebook, Pinterest, LinkedIn, and WhatsApp when shared. Improve your click-through rate by including relevant details, such as an attention-grabbing image.','siteseo').'<p>
        
        <div class="siteseo-notice">
            <span class="dashicons dashicons-info"></span>
            <div>
                <p> '.
		/* translators: placeholders are just <strong> tag */ 
		wp_kses_post(sprintf(__('We generate the %1$s OG:image %2$s meta in the following sequence:', 'siteseo'), '<strong>', '</strong>')).'</p>
                <ol>
                    <li>'.esc_html__('Custom OG image from the SEO metabox', 'siteseo').'</li>
                    <li>'.esc_html__('Post thumbnail / Product category thumbnail (Featured image)', 'siteseo').'</li>
                    <li>'.esc_html__('First image in your post content', 'siteseo').'</li>
                    <li>'.esc_html__('Global OG:image set in SEO > Social > OG Card', 'siteseo').'</li>
                </ol>
            </div>
        </div>

        <table class="form-table">
            <tbody>
                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Enable OG date','siteseo').'</th>
                    <td>
                        <label for="facebook_graph_enable">
                        <input id="facebook_graph_enable" type="checkbox" name="siteseo_options[enable_fb_og]" '.(!empty($option_fb_enable_og) ? 'checked="yes"' : 'value="1"').'>'. esc_html__('Enable OG data','siteseo') .'
                        </label>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Default Image','siteseo').'</th>
                    <td>
                        <input id="facebook_org_image_url" autocomplete="off" type="text" name="siteseo_options[fb_image]" value="'.esc_url($option_fb_img).'" palceholder="'.esc_html__('Select your default thumbnail','siteseo').'">
                        <button id="facebook_upload_logo" class="btn btnSecondary">'.esc_html__('Upload a image','siteseo').'</button>
						<p class="description">'.esc_html__('Minimum size: 200x200px, ideal ratio 1.91:1, 8MB max. (e.g., 1640x856px or 3280x1712px for retina screens).','siteseo').'</p>
                        <p class="description">'.esc_html__('If no default image is set, we will use your site icon defined in the Customizer.','siteseo').'</p>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto;">'.esc_html__('Override Default Image','siteseo').'</th>
                    <td>
                        <div class="siteseo_wrap_label">
                            <label for="override_image_tag">
                            <input id="override_image_tag" type="checkbox" name="siteseo_options[fb_default_img]" '.(!empty($option_fb_defult_img) ? 'checked="yes"' : 'value="1"').' >'.esc_html__('Override all og:image tags with this default image, unless a custom og:image has been set in the SEO metabox.','siteseo').'
                            </label>
                        </div>
			<br /><div class="siteseo-notice is-warning"><p>'.
			/* translators: placeholders are just <strong> tag */ 
			wp_kses_post(sprintf(__('Please define a default %1$s OG image %2$s using the field above.', 'siteseo'), '<strong>','</strong>')).'<p></div>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto">'.esc_html__('Link Ownership ID','siteseo').'</th>
                    <td>
                        <input type="text" placeholder="0123456789" name="siteseo_options[fb_owership_id]" value="'.esc_attr($option_fb_ownership).'">
                        <p class="description">'.esc_html__('Enter one or more Facebook Page IDs linked to a URL to enable link editing and instant article publishing.','siteseo').'</p>
                        <div class="siteseo-styles pre"><pre>'.esc_html('<meta property="fb:pages" content="page ID"/>').'</pre></div>
                    </td>
                </tr>

                <tr>
                    <th scope="row" style="user-select:auto">'.esc_html__('Admin ID','siteseo').'</th>
                    <td>
                        <input type="text" placeholder="0123456789" name="siteseo_options[fb_admin_id]" value="'.esc_attr($option_fb_admin_id).'">
                        <p class="description">'.esc_html__('The ID (or a comma-separated list for properties that support multiple IDs) of an app, user of the app, or Page Graph API object.', 'siteseo').'</p>
                        <div class="siteseo-styles pre"><pre>'.esc_html('<meta property="fb:admins" content="admins ID"/>').'</pre></div>
                    </td>
                </tr>

            </tbody>
        </table><input type="hidden" name="siteseo_options[facebook_tab]" value="1">';

    }

    static function save_settings(){
        global $siteseo;

		check_admin_referer('siteseo_social_settings');

		if(!siteseo_user_can('manage_social') || !is_admin()){
			return;
		}

		$options = [];

		if(empty($_POST['siteseo_options'])){
			return;
		}

		if(isset($_POST['siteseo_options']['knowledge_graph_tab'])){

			$options['social_knowledge_type'] = isset($_POST['siteseo_options']['org_type']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_type'])) : '';
			$options['social_knowledge_name'] = isset($_POST['siteseo_options']['org_name']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_name'])) : '';
			$options['social_knowledge_img'] = isset($_POST['siteseo_options']['org_logo']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_logo'])) : '';
			$options['social_knowledge_phone'] = isset($_POST['siteseo_options']['org_contact_number']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_contact_number'])) : '';
			$options['social_knowledge_contact_type'] = isset($_POST['siteseo_options']['org_contact_type']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_contact_type'])) : '';
			$options['social_knowledge_contact_option'] = isset($_POST['siteseo_options']['org_contact_option']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['org_contact_option'])) : '';
		}

		if(isset($_POST['siteseo_options']['social_account_tab'])){
			$options['social_accounts_facebook'] = isset($_POST['siteseo_options']['facebook']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['facebook'])) : '';
			$options['social_accounts_twitter'] = isset($_POST['siteseo_options']['twitter']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['twitter'])) : '';
			$options['social_accounts_instagram'] = isset($_POST['siteseo_options']['instagram']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['instagram'])) : '';
			$options['social_accounts_youtube'] = isset($_POST['siteseo_options']['youtube']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['youtube'])) : '';
			$options['social_accounts_pinterest'] = isset($_POST['siteseo_options']['pinterest']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['pinterest'])) : '';
			$options['social_accounts_additional'] = isset($_POST['siteseo_options']['additional']) ? explode("\n", sanitize_textarea_field(wp_unslash($_POST['siteseo_options']['additional']))) : '';
			$options['social_accounts_additional'] = Util::clean_url($options['social_accounts_additional']); // We accept 1 url per line.
		}

		if(isset($_POST['siteseo_options']['facebook_tab'])){
			$options['social_facebook_og'] = isset($_POST['siteseo_options']['enable_fb_og']);
			$options['social_facebook_img'] = isset($_POST['siteseo_options']['fb_image']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['fb_image'])) : '';
			$options['social_facebook_img_default'] = isset($_POST['siteseo_options']['fb_default_img']);
			$options['social_facebook_link_ownership_id'] = isset($_POST['siteseo_options']['fb_owership_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['fb_owership_id'])) : '';
			$options['social_facebook_admin_id'] = isset($_POST['siteseo_options']['fb_admin_id']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['fb_admin_id'])) : '';
		}

		if(isset($_POST['siteseo_options']['twitter_tab'])){
			$options['social_twitter_card'] = isset($_POST['siteseo_options']['enable_twitter_card']);
			$options['social_twitter_card_img'] = isset($_POST['siteseo_options']['twitter_img']) ? sanitize_url(wp_unslash($_POST['siteseo_options']['twitter_img'])) : '';
			$options['social_twitter_card_img_size'] = isset($_POST['siteseo_options']['image_size']) ? sanitize_text_field(wp_unslash($_POST['siteseo_options']['image_size'])) : '';
		}

        update_option('siteseo_social_option_name' , $options);
    }
}
socialmetas.php000064400000071035151526415240007574 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class SocialMetas{

	static function add_social_graph(){
		global $siteseo;

		if(empty($siteseo->setting_enabled['toggle-social'])){
			return;
		}

		$org_type = !empty($siteseo->social_settings['social_knowledge_type']) && $siteseo->social_settings['social_knowledge_type'] !== 'none' ? $siteseo->social_settings['social_knowledge_type'] : '';
		$org_name = !empty($siteseo->social_settings['social_knowledge_name']) ? $siteseo->social_settings['social_knowledge_name'] : ''; 
		$org_logo = !empty($siteseo->social_settings['social_knowledge_img']) ? $siteseo->social_settings['social_knowledge_img'] : '';
		$org_number = !empty($siteseo->social_settings['social_knowledge_phone']) ? $siteseo->social_settings['social_knowledge_phone'] : '';
		$org_contact_type = !empty($siteseo->social_settings['social_knowledge_contact_type']) ? $siteseo->social_settings['social_knowledge_contact_type'] : '';
		$org_contact_option = !empty($siteseo->social_settings['social_knowledge_contact_option']) ? $siteseo->social_settings['social_knowledge_contact_option'] : '';

		$fb_account = !empty($siteseo->social_settings['social_accounts_facebook']) ? $siteseo->social_settings['social_accounts_facebook'] : '';
		$twitter_account = !empty($siteseo->social_settings['social_accounts_twitter']) ? $siteseo->social_settings['social_accounts_twitter'] : '';
		$insta_account = !empty($siteseo->social_settings['social_accounts_instagram']) ? $siteseo->social_settings['social_accounts_instagram'] : '';
		$yt_account = !empty($siteseo->social_settings['social_accounts_youtube']) ? $siteseo->social_settings['social_accounts_youtube'] : '';
		$pt_account = !empty($siteseo->social_settings['social_accounts_pinterest']) ? $siteseo->social_settings['social_accounts_pinterest'] : '';

		//description
		$site_url = get_site_url();
		$site_description = get_bloginfo('name');
		$site_language = get_bloginfo('language');

		// logo
		$logo_id = attachment_url_to_postid($org_logo);

		// Defaults
		$logo_width  = '';
		$logo_height = '';

		// Get image dimensions if attachment exists
		if(!empty($logo_id)){
			$image_data = wp_get_attachment_image_src($logo_id, 'full');
			if(!empty($image_data)){
				$logo_width = $image_data[1];
				$logo_height = $image_data[2];
			}
		}

		//JSON-LD data
		$json_ld = [
			'@context' => 'https://schema.org',
			'@type' => $org_type ? esc_html($org_type) : 'Organization',
			'@id' => esc_url(trailingslashit($site_url) . '#' . $org_type),
			'name' => esc_html($org_name),
			'url' => esc_url($site_url),
			'logo' => array_filter([
				'@type' => 'ImageObject',
				'@id' => esc_url(trailingslashit($site_url) . '#logo'),
				'url' => esc_url($org_logo),
				'contentUrl' => esc_url($org_logo),
				'caption' => esc_html($org_name),
				'inLanguage' => esc_html($site_language),
				'width' => $logo_width,
				'height' => $logo_height,
			]),
			'description' => esc_html($site_description),
		];

		//contact point
		if(!empty($org_contact_type) && !empty($org_number)){
			$json_ld['contactPoint'] = [
				'@type' => 'ContactPoint',
				'contactType' => esc_html($org_contact_type),
				'telephone' => esc_html($org_number),
			];

			if(!empty($org_contact_option) && $org_contact_option !== 'None'){
				$contact_point['contactOption'] = esc_html($org_contact_option);
			}
		}

		$x_url = 'https://x.com/'.$twitter_account;

		$same_as = array_filter([
			esc_url($fb_account), 
			esc_url($x_url), 
			esc_url($insta_account), 
			esc_url($yt_account), 
			esc_url($pt_account)
		]);

		if(!empty($same_as)){
			$json_ld['sameAs'] = array_values($same_as);
		}

		// Output JSON-LD script
		echo '<script type="application/ld+json">';
		echo wp_json_encode($json_ld, JSON_UNESCAPED_SLASHES);
		echo '</script>';
	}

	static function fb_graph(){
		global $siteseo, $post;

		if(empty($siteseo->setting_enabled['toggle-social']) || empty($siteseo->social_settings['social_facebook_og'])){
			return;
		}

		$fb_page_id = !empty($siteseo->social_settings['social_facebook_link_ownership_id']) ? $siteseo->social_settings['social_facebook_link_ownership_id'] : '';
		$fb_link_owership = !empty($siteseo->social_settings['social_facebook_admin_id']) ? $siteseo->social_settings['social_facebook_admin_id'] : '';
		$og_url = get_home_url();
		$og_sitename = get_bloginfo('name');
		
		// Check
		$post_id = isset($post) && is_object($post) ? $post->ID : '';
		$og_title = get_the_title();
		$og_description = get_bloginfo('description');
		$og_img = !empty($siteseo->social_settings['social_facebook_img']) ? $siteseo->social_settings['social_facebook_img'] : '';

		// Get post types and taxonomies
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		
		// home site page
		if(is_home() && is_front_page()){
			$og_title = !empty($siteseo->titles_settings['titles_home_site_title']) ? $siteseo->titles_settings['titles_home_site_title'] : $og_title;
			$og_description = !empty($siteseo->titles_settings['titles_home_site_desc']) ? $siteseo->titles_settings['titles_home_site_desc'] : $og_description;
		}
		
		// single post types
		foreach($post_types as $post_type){
			
			// shop page woocommerces
			if(function_exists('is_shop') && is_shop()){
				$shop_page_id = !defined('SITEPAD') ? wc_get_page_id('shop') : kkart_get_page_id('shop');
				
				$archive_title = '';
				$archive_desc = '';
				
				if(is_post_type_archive()){
					$obj = get_queried_object();
					
					if(!empty($obj) && isset($obj->name)){
						$archive_title = !empty($obj->labels->name) ? $obj->labels->name : '';
						$archive_desc  = !empty($obj->description) ? $obj->description : '';
					}
				}
				
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_fb_title', true))){
					$og_title = get_post_meta($shop_page_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($shop_page_id, '_siteseo_titles_title', true))){
					$og_title = get_post_meta($shop_page_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_archive_titles']['product']['archive_title'])){
					$og_title = $siteseo->titles_settings['titles_archive_titles']['product']['archive_title'];
				} else {
					$og_title = $archive_title;
				}
				
				
				$og_description = !empty(get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true)) ? get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true) : $og_description;
							
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true))){
					$og_description = get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($shop_page_id, '_siteseo_titles_desc', true))){
					$og_description = get_post_meta($shop_page_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_archive_titles']['product']['archive_desc'])){
					$og_description = $siteseo->titles_settings['titles_archive_titles']['product']['archive_desc'];
				} else {
					$og_description = $archive_desc;
				}
				
				$og_description = esc_attr(\SiteSEO\TitlesMetas::replace_variables($og_description));
				
				// OG:IMG
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_fb_img', true))){
					$og_img = get_post_meta($shop_page_id, '_siteseo_social_fb_img', true);
				} else if(get_the_post_thumbnail_url($post, 'full')){
					$og_img = get_the_post_thumbnail_url($post, 'full');
				} else {
					$og_img = !empty($siteseo->social_settings['social_facebook_img']) ? $siteseo->social_settings['social_facebook_img'] : '';
				}
				
				$og_url = urldecode(get_permalink($shop_page_id));
				break;
			}
			
			// archive page
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				
				$archive_title = '';
				$archive_desc = '';
				
				if(is_post_type_archive()){
					$obj = get_queried_object();
					
					if(!empty($obj) && isset($obj->name)){
						$archive_title = !empty($obj->labels->name) ? $obj->labels->name : '';
						$archive_desc  = !empty($obj->description) ? $obj->description : '';
					}
				}
				
				$og_title = !empty($siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_title']) ? $siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_title'] : $archive_title;
				$og_description = !empty($siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_desc']) ? $siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_desc'] : $archive_desc;
				
			}
			
			// blog page
			if(is_home() && !is_front_page()){
				$post_id = get_option('page_for_posts');
				
				//OG:title
				if(!empty(get_post_meta($post_id, '_siteseo_social_fb_title', true))){
					$og_title = get_post_meta($post_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_title', true))){
					$og_title = get_post_meta($post_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'])){
					$og_title = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'];
				} else{
					$og_title = $og_title;
				}

				// og:description
				if(!empty(get_post_meta($post_id, '_siteseo_social_fb_desc', true))){
					$og_description = get_post_meta($post_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_desc', true))){
					$og_description = get_post_meta($post_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'])){
					$og_description = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'];
				} elseif(get_the_excerpt($post_id)){
					$og_description = wp_trim_words(get_the_excerpt($post_id), 50);
				}
			}
			
			if(is_singular($post_type->name)){
				
				if(!empty(get_post_meta($post_id, '_siteseo_social_fb_title', true))){
					$og_title = get_post_meta($post_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_title', true))){
					$og_title = get_post_meta($post_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'])){
					$og_title = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'];
				} else{
					$og_title = $og_title;
				}
				
				
				// og:description
				if(!empty(get_post_meta($post_id, '_siteseo_social_fb_desc', true))){
					$og_description = get_post_meta($post_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_desc', true))){
					$og_description = get_post_meta($post_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'])){
					$og_description = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'];
				} elseif(get_the_excerpt($post_id)){
					$og_description = wp_trim_words(get_the_excerpt($post_id), 50);
				}
				
				// OG:IMG
				if(!empty(get_post_meta($post_id, '_siteseo_social_fb_img', true))){
					$og_img = get_post_meta($post_id, '_siteseo_social_fb_img', true);
				} else if(get_the_post_thumbnail_url($post, 'full')){
					$og_img = get_the_post_thumbnail_url($post, 'full');
				} else {
					$og_img = !empty($siteseo->social_settings['social_facebook_img']) ? $siteseo->social_settings['social_facebook_img'] : '';
				}

				$og_url = urldecode(get_permalink($post_id));
				break;
			}
		}

		//  taxonomies
		foreach($taxonomies as $taxonomy){
			if(is_tax($taxonomy->name) || is_category() || is_tag()){
				$term = get_queried_object();
				$term_id = $term->term_id;	
				
				// og:title
				if(!empty(get_term_meta($term_id, '_siteseo_social_fb_title', true))){
					$og_title = get_term_meta($term_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_term_meta($term_id, '_siteseo_titles_title', true))){
					$og_title = get_term_meta($term_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['title'])){
					$og_title = $siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['title'];
				} else{
					$og_title = $og_title;
				}
								
				// og:description
				if(!empty(get_term_meta($term_id, '_siteseo_social_fb_desc', true))){
					$og_description = get_term_meta($term_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_term_meta($term_id, '_siteseo_titles_desc', true))){
					$og_description = get_term_meta($term_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['description'])){
					$og_description = $siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['description'];
				} else{
					$og_description = wp_strip_all_tags(term_description($term_id));
				}
				
				$og_img = !empty(get_term_meta($term_id, '_siteseo_social_fb_img', true)) ? get_term_meta($term_id, '_siteseo_social_fb_img', true) : $og_img;
				$og_url = urldecode(get_term_link($term_id));
				break;
			}
		}
		
		$og_title = esc_attr(\SiteSEO\TitlesMetas::replace_variables($og_title));
		$og_description = esc_attr(\SiteSEO\TitlesMetas::replace_variables($og_description));

		if(!empty($og_img)){
			$og_img = sanitize_url($og_img);
			$og_img_width = 0;
			$og_img_height = 0;

			if(!empty($og_img)){
				$image_info = @getimagesize($og_img);

				if($image_info !== false){
					$og_img_width = $image_info[0];
					$og_img_height = $image_info[1];
				}
			}
		}

		// Setting og:type
		if(is_home() || is_front_page()){
			$og_type = 'website'; // default website
		} elseif(is_singular('product') || is_singular('download')){
			$og_type = 'product';
		} elseif(is_singular()){
			$og_type = 'article';
		} elseif(is_search() || is_archive() || is_404()){
			$og_type = 'object';
		}

		if(!empty($og_url)){
			echo '<meta property="og:url" content="'.esc_html($og_url).'" />';
		}

		if(!empty($og_sitename)){
			echo '<meta property="og:site_name" content="'.esc_html($og_sitename).'" />';
		}

		if(function_exists('get_locale')){
			echo '<meta property="og:locale" content="'.esc_html(get_locale()).'" />';
		}

		if(!empty($og_type)){
			echo '<meta property="og:type" content="'.esc_attr($og_type).'" />';
		}

		if(!empty($og_title)){
			echo '<meta property="og:title" content="'.esc_html($og_title).'" />';
		}

		if(!empty($og_description)){
			echo '<meta property="og:description" content="'.esc_html($og_description).'" />';
		}

		if(!empty($og_img)){
			echo '<meta property="og:image" content="'.esc_html($og_img).'" />';

			if(is_ssl()){
				echo '<meta property="og:secure_url" content="'.esc_html($og_img).'" />';
			}
		}

		if(!empty($og_img_height)){
			echo '<meta property="og:image:height" content="'.esc_attr($og_img_height).'" />';
		}

		if(!empty($og_img_width)){
			echo '<meta property="og:image:width" content="'.esc_attr($og_img_width).'" />';
		}

		if(!empty($fb_page_id)){
			echo '<meta property="fb:pages" content="'.esc_html($fb_page_id) .'" />';
		}

		if(!empty($fb_link_owership)){
			echo '<meta property="fb:admins" content="'. esc_html($fb_link_owership).'" />';
		}
	}

	static function twitter_card(){
		global $siteseo, $post;

		if(empty($siteseo->setting_enabled['toggle-social']) || empty($siteseo->social_settings['social_twitter_card'])){
			return;
		}

		$site_url = get_home_url();
		$twitter_user_name = !empty($siteseo->social_settings['social_accounts_twitter']) ? $siteseo->social_settings['social_accounts_twitter'] : '';

		$post_id = isset($post) && is_object($post) ? $post->ID : '';
		$site_title = get_the_title();
		$site_description = get_bloginfo('description');
		$twitter_img = !empty($siteseo->social_settings['social_twitter_card_img']) ? $siteseo->social_settings['social_twitter_card_img'] : '';
		
		if(empty($twitter_img)){
			$twitter_img = !empty($siteseo->social_settings['social_facebook_img']) ? $siteseo->social_settings['social_facebook_img'] : '';
		}
		
		// home site page
		if(is_home() && is_front_page()){
			$site_title = !empty($siteseo->titles_settings['titles_home_site_title']) ? $siteseo->titles_settings['titles_home_site_title'] : $site_title;
			$site_description = !empty($siteseo->titles_settings['titles_home_site_desc']) ? $siteseo->titles_settings['titles_home_site_desc'] : $site_description;
		}

		// types and taxonomies
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		// single post types
		foreach($post_types as $post_type){
			
			// woocommerce
			if(function_exists('is_shop') && is_shop()){
				$shop_page_id = !defined('SITEPAD') ? wc_get_page_id('shop') : kkart_get_page_id('shop');
				
				$archive_title = '';
				$archive_desc = '';
				
				// if all x-meta tags empty then use og option is enabled
				$use_og = (empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_img', true)));
				
				if(is_post_type_archive()){
					$obj = get_queried_object();
					
					if(!empty($obj) && isset($obj->name)){
						$archive_title = !empty($obj->labels->name) ? $obj->labels->name : '';
						$archive_desc  = !empty($obj->description) ? $obj->description : '';
					}
				}
				
				// twitter:title
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_twitter_title', true))){
					$site_title = get_post_meta($shop_page_id, '_siteseo_social_twitter_title', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($shop_page_id, '_siteseo_social_fb_title', true))){ 
					$site_title = get_post_meta($shop_page_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($shop_page_id, '_siteseo_titles_title', true))){
					$site_title = get_post_meta($shop_page_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_archive_titles']['product']['archive_title'])){
					$site_title = $siteseo->titles_settings['titles_archive_titles']['product']['archive_title'];
				} else {
					$site_title = $archive_title;
				}
							
				
				// twitter:description
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_twitter_desc', true))){
					$site_description = get_post_meta($shop_page_id, '_siteseo_social_twitter_desc', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true))){ 
					$site_description = get_post_meta($shop_page_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($shop_page_id, '_siteseo_titles_desc', true))){
					$site_description = get_post_meta($shop_page_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_archive_titles']['product']['archive_desc'])){
					$site_description = $siteseo->titles_settings['titles_archive_titles']['product']['archive_desc'];
				} else {
					$site_description = $archive_desc;
				}
				
				// twitter:image
				if(!empty(get_post_meta($shop_page_id, '_siteseo_social_twitter_img', true))){
					$twitter_img = get_post_meta($shop_page_id, '_siteseo_social_twitter_img', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($shop_page_id, '_siteseo_social_fb_img', true))){ 
					$twitter_img = get_post_meta($shop_page_id, '_siteseo_social_fb_img', true);
				}  elseif(get_the_post_thumbnail_url($post, 'full')){
					$twitter_img = get_the_post_thumbnail_url($post, 'full');
				} else {
					$twitter_img = isset($siteseo->social_settings['social_twitter_card_img']) ? $siteseo->social_settings['social_twitter_card_img'] : '';
				}

				$site_url = urldecode(get_permalink($shop_page_id));
				break;
			}
			
			// archive page
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				
				$archive_title = '';
				$archive_desc = '';
				
				if(is_post_type_archive()){
					$obj = get_queried_object();
					
					if(!empty($obj) && isset($obj->name)){
						$archive_title = !empty($obj->labels->name) ? $obj->labels->name : '';
						$archive_desc  = !empty($obj->description) ? $obj->description : '';
					}
				}
				
				$site_title = !empty($siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_title']) ? $siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_title'] : $archive_title;
				$site_description = !empty($siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_desc']) ? $siteseo->titles_settings['titles_archive_titles'][$post_type->name]['archive_desc'] : $archive_desc;
				
			}
			
			// blog page
			if(is_home() && !is_front_page()){
				$post_id = get_option('page_for_posts');
				$use_og = (empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_img', true)));
				
				// twitter:title
				if(!empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true))){
					$site_title = get_post_meta($post_id, '_siteseo_social_twitter_title', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($post_id, '_siteseo_social_fb_title', true))){ 
					$site_title = get_post_meta($post_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_title', true))){
					$site_title = get_post_meta($post_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'])){
					$site_title = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'];
				} else{
					$site_title = $site_title;
				}
				
				// twitter:description
				if(!empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true))){
					$site_description = get_post_meta($post_id, '_siteseo_social_twitter_desc', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($post_id, '_siteseo_social_fb_desc', true))){ 
					$site_description = get_post_meta($post_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_desc', true))){
					$site_description = get_post_meta($post_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'])){
					$site_description = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'];
				} elseif(!empty(get_the_excerpt($post_id))){
					$site_description = wp_trim_words(get_the_excerpt($post_id), 50);
				}
			}
			
			if(is_singular($post_type->name)){
				
				$use_og = (empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_img', true)));
				
				// twitter:title
				if(!empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true))){
					$site_title = get_post_meta($post_id, '_siteseo_social_twitter_title', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($post_id, '_siteseo_social_fb_title', true))){ 
					$site_title = get_post_meta($post_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_title', true))){
					$site_title = get_post_meta($post_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'])){
					$site_title = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['title'];
				} else{
					$site_title = $site_title;
				}
				
				
				// twitter:description
				if(!empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true))){
					$site_description = get_post_meta($post_id, '_siteseo_social_twitter_desc', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($post_id, '_siteseo_social_fb_desc', true))){ 
					$site_description = get_post_meta($post_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_post_meta($post_id, '_siteseo_titles_desc', true))){
					$site_description = get_post_meta($post_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'])){
					$site_description = $siteseo->titles_settings['titles_single_titles'][$post_type->name]['description'];
				} else{
					$site_description = wp_trim_words(get_the_excerpt($post_id), 50);
				}

				// twitter:image
				if(!empty(get_post_meta($post_id, '_siteseo_social_twitter_img', true))){
					$twitter_img = get_post_meta($post_id, '_siteseo_social_twitter_img', true);
				} elseif(!empty($use_og) && !empty(get_post_meta($post_id, '_siteseo_social_fb_img', true))){ 
					$twitter_img = get_post_meta($post_id, '_siteseo_social_fb_img', true);
				} else if(get_the_post_thumbnail_url($post, 'full')){
					$twitter_img = get_the_post_thumbnail_url($post, 'full');
				} else {
					$twitter_img = isset($siteseo->social_settings['social_twitter_card_img']) ? $siteseo->social_settings['social_twitter_card_img'] : '';
				}

				$site_url = urldecode(get_permalink($post_id));
				break;
			}
		}

		//taxonomies
		foreach($taxonomies as $taxonomy){
			
			if(is_tax($taxonomy->name) || is_category() || is_tag()){
				$term = get_queried_object();
				$term_id = $term->term_id;
				
				$use_og = (empty(get_post_meta($post_id, '_siteseo_social_twitter_title', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_desc', true)) && empty(get_post_meta($post_id, '_siteseo_social_twitter_img', true)));
				//twitter:title
				if(!empty(get_term_meta($term_id, '_siteseo_social_twitter_title', true))){
					$site_title = get_term_meta($term_id, '_siteseo_social_twitter_title', true);
				} elseif(!empty($use_og) && !empty(get_term_meta($term_id, '_siteseo_social_fb_title', true))){ 
					$site_title = get_term_meta($term_id, '_siteseo_social_fb_title', true);
				} elseif(!empty(get_term_meta($term_id, '_siteseo_titles_title', true))){
					$site_title = get_term_meta($term_id, '_siteseo_titles_title', true);
				} elseif(!empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['title'])){
					$site_title = $siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['title'];
				} else{
					$site_title = $site_title;
				}
				
				// twitter description
				if(!empty(get_term_meta($term_id, '_siteseo_social_twitter_desc', true))){
					$site_description = get_term_meta($term_id, '_siteseo_social_twitter_desc', true);
				} elseif(!empty($use_og) && !empty(get_term_meta($term_id, '_siteseo_social_fb_desc', true))){ 
					$site_description = get_term_meta($term_id, '_siteseo_social_fb_desc', true);
				} elseif(!empty(get_term_meta($term_id, '_siteseo_titles_desc', true))){
					$site_description = get_term_meta($term_id, '_siteseo_titles_desc', true);
				} elseif(!empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['description'])){
					$site_description = $siteseo->titles_settings['titles_tax_titles'][$taxonomy->name]['description'];
				} else{
					$site_description = wp_strip_all_tags(term_description($term_id));
				}
								
				$twitter_img = !empty(get_term_meta($term_id, '_siteseo_social_twitter_img', true)) ? get_term_meta($term_id, '_siteseo_social_twitter_img', true) : '';
				
				if(empty($twitter_img) && !empty($use_og) && !empty(get_term_meta($term_id, '_siteseo_social_fb_img', true))){
					$twitter_img = get_term_meta($term_id, '_siteseo_social_fb_img', true);
				} else{
					$twitter_img = $twitter_img;
				}
				
				$site_url = urldecode(get_term_link($term_id));
				break;
			}
		}
		
		$site_title = esc_attr(\SiteSEO\TitlesMetas::replace_variables($site_title));
		$site_description = esc_attr(\SiteSEO\TitlesMetas::replace_variables($site_description));
		$x_image_size = 'summary';
		if(!empty($siteseo->social_settings['social_twitter_card_img_size']) && $siteseo->social_settings['social_twitter_card_img_size'] == 'Large'){
			$x_image_size = 'summary_large_image';
		}
		echo '<meta name="twitter:card" content="'.esc_attr($x_image_size).'"/>';
		
		echo '<meta name="twitter:locale" content="'.esc_html(get_locale()).'"/>';
		
		if(!empty($site_title)){
			echo '<meta name="twitter:title"  content="'.esc_html($site_title).'"/>';
		}
		
		if(!empty($site_description)){
			echo '<meta name="twitter:description" content="'.esc_html($site_description).'"/>';
		}
		
		if(!empty($site_url)){
			echo '<meta name="twitter:url" content="'.esc_html($site_url).'"/>';
		}
		
		if(!empty($twitter_user_name)){
			$twitter_user_name = trim($twitter_user_name, '@');
			echo '<meta name="twitter:site" content="@'.esc_html($twitter_user_name).'"/>';
		}
		
		if(!empty($twitter_img)){
			echo '<meta name="twitter:image" content="'.esc_html($twitter_img).'"/>';
		}
	}
}
tableofcontent.php000064400000012407151526415240010275 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

use DOMDocument;
use DOMXPath;

class TableofContent{
	
	static function enable_toc(){
        global $siteseo;

        if(empty($siteseo->setting_enabled['toggle-advanced']) || empty($siteseo->advanced_settings['toc_enable'])){
            return;
        }

        add_filter('the_content', '\SiteSEO\TableofContent::add_ids_to_headings');
    }

	static function render_toc(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced']) || empty($siteseo->advanced_settings['toc_enable'])){
			return;
		}

		static $siteseo_toc_run = false;

		if(!empty($siteseo_toc_run)){
			return '<p style="padding: 1rem; background-color:#fff3cd; color:#664d03; border:1px solid #ffe69c; border-radius: 0.375rem">'.esc_html__('Table of content shortcode can be used only once on a page, this page is using the shortcode more than once. Please remove the extra table of content shortcodes for this warning to go away.', 'siteseo').'</p>';
		}

		$options = get_option('siteseo_advanced_option_name');
		//$options = $siteseo->advanced_settings;
		
		$content = get_the_content();

		if(empty($content)){
			return;
		}

		$heading_type = (!empty($options['toc_heading_type']) ? $options['toc_heading_type'] : 'ul');

		$dom = new DOMDocument();
		$internalErrors = libxml_use_internal_errors(true);
		$dom->preserveWhiteSpace = false;

		$html = '';

		if($dom->loadHTML('<?xml encoding="utf-8" ?>' . $content)){
			$xpath = new DOMXPath($dom);

			$heading_list = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
			
			$headings_to_scan = [];
			foreach($heading_list as $h){
				if(!empty($options['toc_excluded_headings']) && is_array($options['toc_excluded_headings']) && in_array($h, $options['toc_excluded_headings'])){
					continue;
				}

				$headings_to_scan[] = '//'.$h;
			}

			if(empty($headings_to_scan)){
				return;
			}

			$headings_to_scan = implode('|', $headings_to_scan);
			
			// The imploded string will look like this //h1|//h2|//h3|//h4|//h5|//h6 
			$headings = $xpath->query($headings_to_scan);

			if(empty($headings)){
				return;
			}

			$last_h = 0;
			$open_ul = 0;
			
			$html .= '<style>.siteseo-toc-wrapper { padding: 20px; border: 1px solid #a2a9b1; background-color: #f8f9fa;}.siteseo-toc-wrapper p { display:flex; align-items:center; gap: 10px; font-size: 1.5rem; font-weight: 500; margin: 0 0 10px 0;}.siteseo-toc-wrapper > '.esc_html($heading_type).' { margin: 0; padding: 0;}.siteseo-toc-wrapper p>label { font-weight: 400; font-size: 0.9rem;}#siteseo-toc-toggle~span { cursor: pointer;}#siteseo-toc-toggle:checked~.siteseo-toc-hide,p:has(#siteseo-toc-toggle:checked) ~ '.esc_html($heading_type).' { display: none;}#siteseo-toc-toggle:not(:checked) ~ .siteseo-toc-hide{ display: inline;}#siteseo-toc-toggle:not(:checked) ~ .siteseo-toc-show { display: none;}</style>
			<div class="siteseo-toc-wrapper">
			<p>'.(!empty($options['toc_label']) ? esc_html($options['toc_label']) : esc_html__('Table of Content', 'siteseo')).' <label for="siteseo-toc-toggle">
			<input type="checkbox" style="display:none;" id="siteseo-toc-toggle" name="siteseo-toc-toggle"/>
			[<span class="siteseo-toc-hide">hide</span><span class="siteseo-toc-show">show</span>]</label></p>
			<'.esc_html($heading_type).'>';

			foreach($headings as $heading){
				$title = trim(wp_strip_all_tags($heading->nodeValue));
				$id = $heading->getAttribute('id');
				$current_h = (int) substr($heading->tagName, 1);
				
				if(empty($id)){
					$id = '#'.self::title_to_id($title);
				}else{
					$id = '#'.$id;
				}

				if($current_h > $last_h){				
					$html .= '<'.esc_html($heading_type).'>';
					$open_ul++;
				}else{
					while($current_h <= $open_ul){
						$html .= '</'.esc_html($heading_type).'>';
						$open_ul--;
					}
				}

				$html .= '<li><a href="'.esc_attr($id).'">'.esc_html($title).'</a></li>';
				$last_h = $current_h;
			}

			$html .= '</'.esc_html($heading_type).'></div>';
			
			$siteseo_toc_run = true;
		}

		return $html;
	}

	// Converts heading text content to ID to be used as link
	static function title_to_id($title){
		
		$id = trim(wp_strip_all_tags($title));
		$id = remove_accents($title);
		$id = sanitize_title_with_dashes($id);
		$id = urlencode($id);

		return $id;
	}

	static function add_ids_to_headings($content){

		if(empty($content)){
			return $content;
		}

		// If the page does not have the shortcode then we don't need to update the id's in the heading.
		if(!has_shortcode($content, 'siteseo_toc')){
			return $content;
		}
		
		$dom = new DOMDocument();
		$internalErrors = libxml_use_internal_errors(true);
		$dom->preserveWhiteSpace = false;

		$html = '';

		if($dom->loadHTML('<?xml encoding="utf-8" ?>' . $content)){
			$xpath = new DOMXPath($dom);

			$headings = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');

			if(empty($headings)){
				return;
			}

			foreach($headings as $heading){
				$title = trim(wp_strip_all_tags($heading->nodeValue));
				$id = $heading->getAttribute('id');
				
				if(!empty($id)){
					continue;
				}
				
				if(empty($title)){
					continue;
				}
				
				$id = self::title_to_id($title);

				$heading->setAttribute('id', $id);
			}

			$content = $dom->saveHTML($dom->documentElement);
		}

		return $content;

	}

}instantindexing.php000064400000021554151526415240010477 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class InstantIndexing{
	
	static function bing_txt_file(){
		global $wp, $siteseo;
		
		$request = home_url($wp->request);
		if(empty($request)){
			return;
		}

		$api_key = $siteseo->instant_settings['instant_indexing_bing_api_key'];
		$api_url = trailingslashit(home_url()) . $api_key . '.txt';
		
		if($request == $api_url){
			header('X-Robots-Tag: noindex');
			header('Content-Type: text/plain');
			status_header(200);

			echo esc_html($api_key);
			die();
		}
	}
	
	static function submit_urls_to_google($urls){
		$access_token = self::get_google_auth_token();

		if(empty($access_token)){
			return;
		}

		$boundary = wp_rand();
		$batch_body = '';
		$options = get_option('siteseo_instant_indexing_option_name');
		$type = !empty($options['instant_indexing_google_action']) ? $options['instant_indexing_google_action'] : 'URL_UPDATED';
		
		switch($type){
			case 'remove_urls':
				$type = 'URL_DELETED';
				break;
			
			case 'update_urls':
				$type = 'URL_UPDATED';
				break;
		}
		
		// Creating a batch request
		foreach($urls as $url){
			$post_data = wp_json_encode(['url' => $url, 'type' => $type]);

			$batch_body .= '--'.$boundary.PHP_EOL;
			$batch_body .= 'Content-Type: application/http'.PHP_EOL;
			$batch_body .= 'Content-Transfer-Encoding: binary'.PHP_EOL;
			$batch_body .= 'Content-ID: <'.esc_url($url).'>'.PHP_EOL.PHP_EOL;
			$batch_body .= 'POST /v3/urlNotifications:publish HTTP/1.1'.PHP_EOL;
			$batch_body .= 'Content-Type: application/json' . PHP_EOL;
			$batch_body .= 'accept: application/json'.PHP_EOL;
			$batch_body .= 'content-length: '.strlen($post_data).PHP_EOL.PHP_EOL;
			$batch_body .= $post_data.PHP_EOL;
		}

		$batch_body .= '--'.$boundary.'--';

		$response = wp_remote_post('https://indexing.googleapis.com/batch', [
			'body' => $batch_body,
			'headers' => [
				'Content-Type' => 'multipart/mixed; boundary='.$boundary,
				'Authorization' => 'Bearer ' . $access_token
			],
			'timeout' => 30
		]);
		
		if(is_wp_error($response)){
			$response = ['error' => $response->get_error_message()];
			return;
		}
		
		$res_code = wp_remote_retrieve_response_code($response);

		if($res_code > 299){
			return $response;
		}
		
		$batch_response = self::parse_batch_response($response);

		$response = [
			'status_code' => wp_remote_retrieve_response_code($response),
			'urls' => $batch_response,
			'error' => is_wp_error($response) ? $response->get_error_message() : null
		];

		return $response;
	}

	static function parse_batch_response(&$response){
		$response_headers = wp_remote_retrieve_headers($response);
		$response_headers = $response_headers->getAll();

		$content_type = $response_headers['content-type'];

		$urls = [];

		$content_type = explode(';', $content_type);
		$boundary = false;
		foreach($content_type as $part){
			$part = explode('=', $part, 2);
			if (isset($part[0]) && 'boundary' == trim($part[0])) {
				$boundary = $part[1];
			}
		}

		$res_body = wp_remote_retrieve_body($response);
		$res_body = str_replace('--'.$boundary.'--', '--'.$boundary, $res_body);
		$batch_responses = explode('--'.$boundary, $res_body);
		$batch_responses = array_filter($batch_responses);

		foreach($batch_responses as $batch_response){
			$batch_response = trim($batch_response);
			if(empty($batch_response)){
				continue;
			}

			$batch_response = explode("\r\n\r\n", $batch_response);

			if(empty($batch_response[2])){
				continue;
			}

			$batch_body = json_decode($batch_response[2], true);

			if(empty($batch_body)){
				continue;
			}

			if(!empty($batch_body['urlNotificationMetadata']) && !empty($batch_body['urlNotificationMetadata']['url'])){
				$urls[] = sanitize_url($batch_body['urlNotificationMetadata']['url']);
			}
		}

		return $urls;
	}
	
	static function get_google_auth_token(){
		global $siteseo;
		
		$endpoint = 'https://oauth2.googleapis.com/token';
		$scope = 'https://www.googleapis.com/auth/indexing';
		
		if(!function_exists('openssl_sign')){
			return false;
		}

		$google_api_data = isset($siteseo->instant_settings['instant_indexing_google_api_key']) ? $siteseo->instant_settings['instant_indexing_google_api_key'] : '';
		
		if(empty($google_api_data)){
			return false;
		}

		$google_api_data = json_decode($google_api_data, true);
		if(empty($google_api_data)){
			return;
		}

		// Header
		$headers = wp_json_encode(['alg' => 'RS256', 'typ' => 'JWT']);
		$headers = base64_encode($headers);

		// Claim Set
		$now = time();
		$claims = wp_json_encode([
			'iss' => $google_api_data['client_email'],
			'scope' => 'https://www.googleapis.com/auth/indexing',
			'aud' => 'https://oauth2.googleapis.com/token',
			'exp' => $now + 3600,
			'iat' => $now
		]);

		$claims = base64_encode($claims);

		// Make sure base64 encoding is URL-safe
		$headers = str_replace(['+', '/', '='], ['-', '_', ''], $headers);
		$claim = str_replace(['+', '/', '='], ['-', '_', ''], $claims);

		// Sign the JWT with the private key
		$signature_input = "$headers.$claim";
		openssl_sign($signature_input, $signature, $google_api_data['private_key'], OPENSSL_ALGO_SHA256);

		$signature = base64_encode($signature);
		$signature = str_replace(['+', '/', '='], ['-', '_', ''], $signature);

		// JWT Token
		$jwt_assertion = "$signature_input.$signature";

		// OAuth2 Request
		$post_data = http_build_query([
			'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
			'assertion' => $jwt_assertion
		]);

		$response = wp_remote_post($endpoint, [
			'body' => $post_data,
			'headers' => [
				'Content-Type' => 'application/x-www-form-urlencoded',
			]
		]);

		if(is_wp_error($response)){
			return false;
		}

		$body = json_decode(wp_remote_retrieve_body($response), true);
		return isset($body['access_token']) ? $body['access_token'] : false;

	}

	/**
	 * Sends request to index now api with list of urls and key and key location.
	 *
	 * Key location is just the URL to a file which has the same name as the Key
	 * as key.txt and the content in it is the key as well. This is a virtual file.
	 *
	 * @param array $urls List of URLs to submit.
	 * @param string $api_key bing key.
	 *
	 * @return array with 'status_code' and response 'body'
	 */
	static function submit_urls_to_bing($urls, $api_key){
        	$host = wp_parse_url(home_url(), PHP_URL_HOST);
		$key_location = trailingslashit(home_url()) . $api_key . '.txt';

		$endpoint = 'https://api.indexnow.org/indexnow/';
		$body = wp_json_encode([
		    'host' => $host, 
		    'key' => $api_key,
				'keyLocation' => $key_location,
		    'urlList' => $urls
		]);

		$response = wp_remote_post($endpoint, [
		    'body' => $body,
		    'headers' => [
		        'Content-Type' => 'application/json',
		        'Accept' => 'application/json'
		    ],
		    'timeout' => 30
		]);

		return [
		    'status_code' => wp_remote_retrieve_response_code($response),
		    'body' => wp_remote_retrieve_body($response)
		];
	}
	
	// Sends request to bing when the status of post changes
	// We will only do it only if the post is published.
	static function on_status_change($new_status, $old_status, $post){

		if($new_status == $old_status){
			return;
		}
		
		if($new_status != 'publish'){
			return;
		}
		
		if(empty($post) || empty($post->post_type)){
			return;
		}
		
		$post_type_object = get_post_type_object($post->post_type);
		
		// Need to make sure we submit posts whos post type is public
		if(empty($post_type_object) || empty($post_type_object->public)){
			return;
		}

		$options = get_option('siteseo_instant_indexing_option_name', []);

		$bing_api_key = !empty($options['instant_indexing_bing_api_key']) ? $options['instant_indexing_bing_api_key'] : '';
		$google_api_key = !empty($options['instant_indexing_google_api_key']) ? $options['instant_indexing_google_api_key'] : '';
		$url = get_permalink($post);

		$url_list = [$url];
		$res_google = null;
		$res_bing   = null;
		
		if(!empty($bing_api_key)){
			$res_bing = self::submit_urls_to_bing($url_list, $bing_api_key);
		}
		
		if(!empty($google_api_key)){
			$res_google = self::submit_urls_to_google($url_list);
		}
		
		self::save_index_history($url_list, $res_google, $res_bing , 'auto');
				
	}
	
	static function save_index_history($urls, $google_response, $bing_response, $source){
		global $siteseo;
		
		$history = $siteseo->instant_settings;

		if(!isset($history['indexing_history'])){
			$history['indexing_history'] = [];
		}

		array_unshift($history['indexing_history'], [
			'time' => time(),
			'urls' => $urls,
			'google_status_code' => !empty($google_response['status_code']) ? $google_response['status_code'] : null,
			'bing_status_code' => !empty($bing_response['status_code']) ? $bing_response['status_code'] : null,
			'source' => !empty($source) ? $source : 'manual', // 'manual' or 'auto'
		]);
		
		$history['indexing_history'] = array_slice($history['indexing_history'], 0, 10);

		update_option('siteseo_instant_indexing_option_name', $history);
	}	
}
googleanalytics.php000064400000063353151526415240010460 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class GoogleAnalytics{

	static function ga_render(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-google-analytics'])){
			return;
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_clarity_enable']) && !empty($siteseo->analaytics_settings['google_analytics_clarity_project_id'])){
			add_action('wp_head', '\SiteSEO\GoogleAnalytics::microsoft_clarity');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_enable']) && !empty($siteseo->analaytics_settings['google_analytics_ga4'])){
			add_action('wp_head', '\SiteSEO\GoogleAnalytics::ga_tracking_code');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_enable'])){
			add_action('wp_footer', '\SiteSEO\GoogleAnalytics::tracking');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_link_tracking_enable'])){
			add_action('wp_footer', '\SiteSEO\GoogleAnalytics::add_tracking_script');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_matomo_enable']) && !empty($siteseo->analaytics_settings['google_analytics_matomo_site_id'])){
			add_action('wp_footer', '\SiteSEO\GoogleAnalytics::matomo_tracking_code');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_other_tracking'])){
			add_action('wp_head', '\SiteSEO\GoogleAnalytics::add_custom_head_script');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_other_tracking_body'])){
			add_action('wp_body_open', '\SiteSEO\GoogleAnalytics::add_custom_body_script');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_other_tracking_footer'])){
			add_action('wp_footer', '\SiteSEO\GoogleAnalytics::add_custom_footer_script');
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_opt_out_edit_choice'])){
			$load_cookies_bar = $siteseo->analaytics_settings['google_analytics_hook'];
			add_action($load_cookies_bar, '\SiteSEO\GoogleAnalytics::render_cookie_bar');
		}
		
	}

	static function render_cookie_bar(){
		global $siteseo;

		if(empty($siteseo->setting_enabled['toggle-google-analytics']) || empty($siteseo->analaytics_settings['google_analytics_disable'])){
			return;
		}

		// Plugin edit pages on which we should not show the cookie notice.
		$page_builders = ['fl_builder', 'elementor-preview', 'ct_builder', 'vc_editable', 'brizy_edit', 'tve', 'pagelayer-live'];

		foreach($page_builders as $builder){
			if(isset($_GET[$builder])){
				return;
			}
		}

		// load setting
		$auto_accept_cookies = !empty($siteseo->analaytics_settings['google_analytics_half_disable']) ? $siteseo->analaytics_settings['google_analytics_half_disable'] : '';
		$cookies_msg = !empty($siteseo->analaytics_settings['google_analytics_opt_out_msg']) ? $siteseo->analaytics_settings['google_analytics_opt_out_msg'] : 'By visiting our site, you agree to our privacy policy regarding cookies, tracking statistics, etc.';
		$accept_btn_msg = !empty($siteseo->analaytics_settings['google_analytics_opt_out_msg_ok']) ? $siteseo->analaytics_settings['google_analytics_opt_out_msg_ok'] : 'Accept';
		$close_btn_msg = !empty($siteseo->analaytics_settings['google_analytics_opt_out_msg_close']) ? $siteseo->analaytics_settings['google_analytics_opt_out_msg_close'] : 'X';
		$edit_btn_msg = !empty($siteseo->analaytics_settings['google_analytics_opt_out_msg_edit']) ? $siteseo->analaytics_settings['google_analytics_opt_out_msg_edit'] : 'Manage cookies';
		$cookies_expir = !empty($siteseo->analaytics_settings['google_analytics_cb_exp_date']) ? $siteseo->analaytics_settings['google_analytics_cb_exp_date'] : '';
		$bar_postion = !empty($siteseo->analaytics_settings['google_analytics_cb_pos']) ? $siteseo->analaytics_settings['google_analytics_cb_pos'] : '' ;
		$bar_width = !empty($siteseo->analaytics_settings['google_analytics_cb_width']) ? $siteseo->analaytics_settings['google_analytics_cb_width'] : '';
		$display_backrop = !empty($siteseo->analaytics_settings['google_analytics_cb_backdrop']) ? true : '';

		// colors load 
		$backdrop_bg = !empty($siteseo->analaytics_settings['google_analytics_cb_backdrop_bg']) ? $siteseo->analaytics_settings['google_analytics_cb_backdrop_bg'] : '';
		$cookiebar_bg = !empty($siteseo->analaytics_settings['google_analytics_cb_bg']) ? $siteseo->analaytics_settings['google_analytics_cb_bg'] : '#ffffff';
		$cookiebar_bg_txt = !empty($siteseo->analaytics_settings['google_analytics_cb_txt_col']) ? $siteseo->analaytics_settings['google_analytics_cb_txt_col'] : '#000000';
		$cookiesbar_bg_lk = !empty($siteseo->analaytics_settings['google_analytics_cb_lk_col']) ? $siteseo->analaytics_settings['google_analytics_cb_lk_col'] : '#0073aa';
		$primary_btn_bg = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_bg']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_bg'] : '#0073aa';
		$primary_btn_bg_hov = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_bg']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_bg'] : '#ffffff';
		$primary_btn_txt = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_col']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_col'] : '#005177';
		$primary_btn_txt_hov = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_col']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_col'] : '#ffffff';
		$sec_btn_bg = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_sec_bg']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_sec_bg'] : '#cccccc';
		$sec_btn_bg_txt = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_sec_col']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_sec_col'] : '#000000';
		$sec_btn_bg_hov = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_sec_bg_hov']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_sec_bg_hov'] : '#aaaaaa';
		$sec_btn_txt_hov = !empty($siteseo->analaytics_settings['google_analytics_cb_btn_sec_col_hov']) ? $siteseo->analaytics_settings['google_analytics_cb_btn_sec_col_hov'] : '#000000';

		//position
		$position_class = '';
		$backdrop = false;
		switch(strtolower($bar_postion)){
			case 'middle':
				$position_class = 'siteseo-cookie-bar-middle';
				$backdrop = true;
				break;
			case 'top':
				$position_class = 'siteseo-cookie-bar-top';
				$backdrop = false;
				break;
			default:
				$position_class = 'siteseo-cookie-bar-bottom';
				$backdrop = false;
		}

		/* Translators: %s is the background color */
		$bar_styles = sprintf(
			'background-color: %s; color: %s;',
			esc_attr($cookiebar_bg),
			esc_attr($cookiebar_bg_txt)
		);

		
		$backdrop_html = '';
		if(!empty($display_backrop) && $backdrop){
			$backdrop_html = '<div id="siteseo-cookie-bar-backdrop" style="background-color:'.esc_attr($backdrop_bg).'" class="siteseo-cookie-bar-backdrop"></div>';
		}

		$css = '<style>
			#siteseo-cookie-bar-accept{
				--primary-btn-bg: '.esc_attr($primary_btn_bg).';
				--primary-btn-text: '.esc_attr($primary_btn_txt).';
				--primary-btn-hover-bg: '.esc_attr($primary_btn_bg_hov).';
				--primary-btn-hover-text: '.esc_attr($primary_btn_txt_hov).';
			}
			#siteseo-cookie-bar-close{
				--secondary-btn-bg: '.esc_attr($sec_btn_bg).';
				--secondary-btn-text: '.esc_attr($sec_btn_bg_txt).';
				--secondary-btn-hover-bg: '.esc_attr($sec_btn_bg_hov).';
				--secondary-btn-hover-text: '.esc_attr($sec_btn_txt_hov).';
			}
		</style>';
		
		$html = $backdrop_html;
		$html .= '<div id="siteseo-cookie-bar" class="siteseo-cookie-bar '.esc_attr($position_class).'" style="'.esc_attr($bar_styles).'" data-half-disable="'.esc_attr($auto_accept_cookies).'">
			<div class="siteseo-cookie-bar-content">
				<span>'.wp_kses_post($cookies_msg).'</span>
				<div class="siteseo-cookie-bar-buttons">
					<button id="siteseo-cookie-bar-accept" class="siteseo-cookie-bar-button siteseo-cookie-bar-primary-btn" style="background-color: '.esc_attr($primary_btn_bg).'; color: '.esc_attr($primary_btn_txt).'">
						'.esc_html($accept_btn_msg).'
					</button>
					<button id="siteseo-cookie-bar-close" class="siteseo-cookie-bar-button siteseo-cookie-bar-secondary-btn" style="background-color: '.esc_attr($sec_btn_bg).'; color: '.esc_attr($sec_btn_bg_txt).'">
						'.esc_html($close_btn_msg).'
					</button>
				</div>
			</div>
		</div>
		<button id="siteseo-cookie-bar-manage-btn" class="siteseo-cookie-bar-button siteseo-cookie-bar-primary-btn" style="background-color: '.$primary_btn_bg.'; color: '.esc_attr($primary_btn_txt).'">
			'.esc_html($edit_btn_msg).'
		</button>';
		
		echo wp_kses_post($html);
	}
	
	static function update_src_tag($tag, $handle, $src){
		global $siteseo;
		
		$tracking_handles = [
			'siteseo-gtag',
			'siteseo-matomo-tracking',
			'siteseo-microsoft-clarity',
			'siteseo-microsoft-clarity-js-after',
			'siteseo-ga-tracking'
		];
		
		if(!in_array($handle, $tracking_handles)){
			return $tag;
		}
		
		if(!empty($siteseo->analaytics_settings['google_analytics_disable']) && !isset($_COOKIE['siteseo-user-consent-accept']) && !isset($_COOKIE['siteseo-user-consent-close'])){
			$tag = str_replace(' src=', ' data-src-siteseo=', $tag);
		}
		
		return $tag;
	}
		
	static function process_script_src($scripts){
		global $siteseo;
		
		if(!empty($siteseo->analaytics_settings['google_analytics_disable']) && !isset($_COOKIE['siteseo-user-consent-accept']) && !isset($_COOKIE['siteseo-user-consent-close'])){
			$scripts = preg_replace('/(<script[^>]*) src=(["\'])(.*?)\\2/i', '$1 data-src-siteseo=$2$3$2', $scripts);
		}
    
		return $scripts;
	}
	
	static function add_custom_head_script(){
		global $siteseo;
        
		$scripts = $siteseo->analaytics_settings['google_analytics_other_tracking'];
       
		$scripts = self::process_script_src($scripts);
        
		echo wp_kses($scripts, [
			'script' => [
				'async' => [],
				'src' => [],
				'data-src-siteseo' => [],
				'type' => []
			]
		]);
	}
	
	static function add_custom_body_script(){
		global $siteseo;
		
		$scripts = $siteseo->analaytics_settings['google_analytics_other_tracking_body'];
		
		$scripts = self::process_script_src($scripts);
		
		echo wp_kses($scripts, [
			'script' => [
				'async' => [],
				'src' => [],
				'data-src-siteseo' => [],
				'type' => []
			]
		]);	
	}
	
	static function add_custom_footer_script(){
		global $siteseo;
		
		$scripts = $siteseo->analaytics_settings['google_analytics_other_tracking_footer'];
		
		$scripts = self::process_script_src($scripts);
		
		echo wp_kses($scripts, [
			'script' => [
				'async' => [],
				'src' => [],
				'data-src-siteseo' => [],
				'type' => []
			]
		]);
	}
	
	static function exclude_user_tracking(){
		global $siteseo;
	
		if(!is_user_logged_in()){
			return false;
		}

		$current_user = wp_get_current_user();
		if(!$current_user){
			return false;
		}

		$excluded_roles = isset($siteseo->analaytics_settings['google_analytics_roles']) ? $siteseo->analaytics_settings['google_analytics_roles'] : [];

		if(empty($excluded_roles)){
			return false;
		}

		foreach($current_user->roles as $user_role){
			if(isset($excluded_roles[$user_role])){
				return true;
			}
		}

		return false;
	}
	
	static function custom_dimensions(){
		global $siteseo;
		$dimensions = [];
		$settings = $siteseo->analaytics_settings;

		// Track Authors
		if(!empty($settings['track_authors']) && $settings['track_authors'] !== 'none'){
			if(is_singular()){
				$author_id = get_post_field('post_author', get_the_ID());
				$author_name = get_the_author_meta('display_name', $author_id);
				$dimensions[$settings['track_authors']] = $author_name;
			}
		}

		// Track Categories
		if(!empty($settings['track_categories']) && $settings['track_categories'] !== 'none'){
			if(is_singular()){
				$categories = get_the_category();
				if(!empty($categories)){
					$category_names = array_map(function($cat){
						return $cat->name;
					}, $categories);
					$dimensions[$settings['track_categories']] = implode(', ', $category_names);
				}
			}
		}

		// Track Tags
		if(!empty($settings['track_tags']) && $settings['track_tags'] !== 'none'){
			if(is_singular()){
				$tags = get_the_tags();
				if(!empty($tags)){
					$tag_names = array_map(function($tag){
						return $tag->name;
					}, $tags);
					$dimensions[$settings['track_tags']] = implode(', ', $tag_names);
				}
			}
		}

		// Track Post Types
		if(!empty($settings['track_post_types']) && $settings['track_post_types'] !== 'none'){
			if(is_singular()){
				$dimensions[$settings['track_post_types']] = get_post_type();
			}
		}

		// Track Logged In Users
		if(!empty($settings['track_user']) && $settings['track_user'] !== 'none'){
			if(is_user_logged_in()){
				$current_user = wp_get_current_user();
				$dimensions[$settings['track_user']] = $current_user->roles[0];
			}
		}

		return $dimensions;
		
	}
	
	static function matomo_tracking_code(){
		global $siteseo;
		
		if(self::exclude_user_tracking()){
			return;
		}
		
		$settings = $siteseo->analaytics_settings;
		
		$tracking_url = !empty($settings['google_analytics_matomo_id']) ? $settings['google_analytics_matomo_id'] : '';
		$site_id = !empty($settings['google_analytics_matomo_site_id']) ? $settings['google_analytics_matomo_site_id'] : '';
		$cross_domain = !empty($settings['google_analytics_matomo_cross_domain']) ? $settings['google_analytics_matomo_cross_domain'] : '';
		$do_not_track = !empty($settings['google_analytics_matomo_dnt']) ? $settings['google_analytics_matomo_dnt'] : '';
		$disable_cookies = !empty($settings['google_analytics_matomo_no_cookies']) ? $settings['google_analytics_matomo_no_cookies'] : '';
		$disable_heatmaps = !empty($settings['google_analytics_matomo_no_heatmaps']) ? $settings['google_analytics_matomo_no_heatmaps'] : '';
		$track_subdomains = !empty($settings['google_analytics_matomo_subdomains']) ? $settings['google_analytics_matomo_subdomains'] : '';
		$track_js_disabled = !empty($settings['google_analytics_matomo_no_js']) ? $settings['google_analytics_matomo_no_js'] : '';
		
		wp_register_script('siteseo-matomo-tracking', false, [], null, [
			'strategy' => true,
			'in_footer' => true,
		]);
		wp_enqueue_script('siteseo-matomo-tracking');
		
		add_filter('script_loader_tag', '\SiteSEO\GoogleAnalytics::update_src_tag', 10, 3);
			wp_add_inline_script('siteseo-matomo-tracking', "var _paq = _paq || [];
			_paq.push(['setSiteId', '".esc_html($site_id)."']);
			_paq.push(['setTrackerUrl', '".esc_html($tracking_url)."']);
            
		    if(".esc_html($cross_domain).") _paq.push(['enableCrossDomainLinking']);
		    if(".esc_html($do_not_track).") _paq.push(['setDoNotTrack', true]);
		    if(".esc_html($disable_cookies).") _paq.push(['disableCookies']);
		    if(".esc_html($disable_heatmaps).") _paq.push(['disableAllHeatmaps']);
		    if(".esc_html($track_subdomains).") _paq.push(['setDocumentTitle', document.domain + '/' + document.title]);

		    _paq.push(['trackPageView']);
		    _paq.push(['enableLinkTracking']);
            
		    (function(){
				var u=\"".esc_html($tracking_url)."\";
		        _paq.push(['setTrackerUrl', u + 'matomo.php']);
				_paq.push(['setSiteId', '".esc_html($site_id)."']);
		        var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
		        g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
		    })();");

		if($track_js_disabled){
			echo '<noscript><img src="'.esc_url($tracking_url.'/matomo.php?idsite='.$site_id.'&rec=1').'" style="border:0" alt="" /></noscript>';
		}
	}
	
	
	static function add_tracking_script(){
		global $siteseo;
		
		if(self::exclude_user_tracking()){
			return;
		}

		echo '<script>
		document.addEventListener("DOMContentLoaded", function() {';

		if(!empty($siteseo->analaytics_settings['google_analytics_link_tracking_enable'])){
			echo 'document.querySelectorAll("a").forEach(function(link){
				if(link.hostname !== location.hostname){
					link.addEventListener("click", function(){
						gtag("event", "click", { "event_category": "External Link", "event_label": link.href });
					});
				}
			});';
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_download_tracking_enable']) && !empty($siteseo->analaytics_settings['google_analytics_download_tracking'])) {

			$fileExtensions = preg_replace('/\s+/', '', $siteseo->analaytics_settings['google_analytics_download_tracking']);
			$fileExtensionsPattern = str_replace('|', '|\\.', $fileExtensions); 

			echo 'document.querySelectorAll("a[href$=\'.' .esc_js(str_replace('|', '\'], a[href$=\'.', $fileExtensions)) . '\']").forEach(function(link) {
				link.addEventListener("click", function() {
					gtag("event", "download", { "event_category": "Download", "event_label": link.href });
				});
			});';
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_affiliate_tracking_enable']) && ! empty($siteseo->analaytics_settings['google_analytics_affiliate_tracking'])){
			$keywords = wp_json_encode( explode( ',', $siteseo->analaytics_settings['google_analytics_affiliate_tracking']));
			echo 'const keywords = '.esc_attr($keywords).';
			document.querySelectorAll("a").forEach(function(link){
				keywords.forEach(function(keyword){
					if(link.href.includes(keyword.trim())){
						link.addEventListener("click", function(){
							gtag("event", "click", { "event_category": "Affiliate/Outbound Link", "event_label": link.href });
						});
					}
				});
			});';
		}

		if(!empty($siteseo->analaytics_settings['google_analytics_phone_tracking'])){
			echo 'document.querySelectorAll("a[href^=\'tel:\']").forEach(function(link){
				link.addEventListener("click", function() {
					gtag("event", "click", { "event_category": "Telephone Link", "event_label": link.href });
				});
			});';
		}

		echo '});
		</script>';
	}
	
	static function tracking(){
		global $siteseo;
		
		if(self::exclude_user_tracking()){
			return;
		}
		
		$settings = $siteseo->analaytics_settings;

		$ga_id = !empty($settings['google_analytics_optimize']) ? $settings['google_analytics_optimize'] : '';
		$conversion_id = !empty($settings['google_analytics_ads']) ? $settings['google_analytics_ads'] : '';
		$optimize_id = !empty($settings['google_analytics_ads']) ? $settings['google_analytics_ads'] : '';
		$remarketing = !empty($settings['google_analytics_remarketing']) ? $settings['google_analytics_remarketing'] : '';
		$anonymize_ip = !empty($settings['google_analytics_ip_anonymization']) ? $settings['google_analytics_ip_anonymization'] : '';
		$enhanced_link = !empty($settings['google_analytics_link_attribution']) ? $settings['google_analytics_link_attribution'] : '';
		$cross_domain = !empty($settings['google_analytics_cross_domain']) ? $settings['google_analytics_cross_domain'] : '';
		$cross_domain_name = !empty($settings['google_analytics_remarketing']) ? $settings['google_analytics_remarketing'] : '';

		//custom dimensions
		$get_custom_dimensions = self::custom_dimensions();
		
		wp_enqueue_script('siteseo-gtag', 'https://www.googletagmanager.com/gtag/js?id=' . esc_attr($ga_id), [], SITESEO_VERSION, [
			'strategy' => 'async',
		]);
		
		add_filter('script_loader_tag', '\SiteSEO\GoogleAnalytics::update_src_tag', 10, 3);
		
		$gtag_config = [
			'anonymize_ip' => $anonymize_ip ? true : false,
			'link_attribution' => $enhanced_link ? true : false,
		];

		if($cross_domain && $cross_domain_name){
			$gtag_config['linker'] = [
				'domains' => [$cross_domain_name]
			];
		}

		// config
		foreach($get_custom_dimensions as $dimension => $value){
			$gtag_config[$dimension] = $value;
		}

		$inline_script = 'window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag("js", new Date());

		window.addEventListener("load", function (){
			var links = document.querySelectorAll("a");
			for(let i = 0; i < links.length; i++){
				links[i].addEventListener("click", function(e) {
					var n = this.href.includes("' . wp_parse_url(home_url(), PHP_URL_HOST) . '");
					if (n == false) {
						gtag("event", "click", {"event_category": "external links","event_label" : this.href});
					}
				});
			}
		});

		gtag("config", "'.esc_js($ga_id).'", '.wp_json_encode($gtag_config).');';

		if($optimize_id){
			$inline_script .= 'gtag("config", "'.esc_js($optimize_id).'");';
		}
		
		if($conversion_id){
			$inline_script .= 'gtag("config", "'.esc_js($conversion_id).'");';
		}
		
		if($remarketing){
			$inline_script .= 'gtag("set", "allow_google_signals", true);';
		}

		wp_add_inline_script('siteseo-gtag', $inline_script);
	}
	
	static function microsoft_clarity(){
		global $siteseo;

		if(self::exclude_user_tracking()){
			return;
		}

		$project_id = !empty($siteseo->analaytics_settings['google_analytics_clarity_project_id']) ? $siteseo->analaytics_settings['google_analytics_clarity_project_id'] : '';

		if(empty($project_id)){
			return;
		}
		
		wp_register_script('siteseo-microsoft-clarity', '', [], SITESEO_VERSION, true);
		
		wp_enqueue_script('siteseo-microsoft-clarity');

		$inline_script = "(function(c,l,a,r,i,t,y){ 
			c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
			t=l.createElement(r);t.async=1;t.src='https://www.clarity.ms/tag/'+i;
			y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
			})(window, document, 'clarity', 'script', '".esc_js($project_id)."');";

		wp_add_inline_script('siteseo-microsoft-clarity', $inline_script);
		
		add_filter('script_loader_tag', '\SiteSEO\GoogleAnalytics::update_src_tag', 10, 3);
		
	}

	static function ga_tracking_code(){
		global $siteseo;
		
		if(self::exclude_user_tracking()){
			return;
		}

		$ga_id = isset($siteseo->analaytics_settings['google_analytics_ga4']) ? esc_attr($siteseo->analaytics_settings['google_analytics_ga4']) : '';
		
		if(empty($ga_id)){
			return;
		}

		wp_enqueue_script('siteseo-ga-tracking', 'https://www.googletagmanager.com/gtag/js?id=' . $ga_id, [], SITESEO_VERSION, true);
		
		add_filter('script_loader_tag', '\SiteSEO\GoogleAnalytics::add_async_attribute', 10, 2);
		
		$inline_script = "
			window.dataLayer = window.dataLayer || [];
			function gtag(){dataLayer.push(arguments);}
			gtag('js', new Date());
			gtag('config', '{$ga_id}');
		";
		
		wp_add_inline_script('siteseo-ga-tracking', $inline_script);

	}
	
	static function add_async_attribute($tag, $handle){
		global $siteseo;
		if('siteseo-ga-tracking' === $handle){
       			
			if(!empty($siteseo->analaytics_settings['google_analytics_disable'])){
				if(isset($_COOKIE['siteseo-user-consent-accept']) && $_COOKIE['siteseo-user-consent-accept'] === 'true'){
					return str_replace(' src', ' async src', $tag);
				} else{
					return str_replace(' src', ' data-src-siteseo', $tag);
				}
			}
		}
		
		return $tag;
	}
	
	/** TODO:: temporary in this file*/	
	 static function handle_custom_redirect(){
		global $post;

		// post types and taxonomies
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');


		$is_singular = false;
		foreach($post_types as $post_type){
			if(is_singular($post_type->name)){
				$is_singular = true;
				break;
			}
		}

		$is_taxonomy = false;
		foreach($taxonomies as $taxonomy){
			if(is_tax($taxonomy->name)){
				$is_taxonomy = true;
				break;
			}
		}

		if($is_singular || is_404() || $is_taxonomy || is_category() || is_tag()){
			if(is_404()){
				$args = array(
					'post_type' => 'siteseo_404',
					'posts_per_page' => 1,
					'meta_query' => array(
						array(
							'key' => '_siteseo_redirections_enabled',
							'value' => 'yes',
							'compare' => '='
						)
					)
				);
				$redirect_posts = get_posts($args);

				if(empty($redirect_posts)){
					return;
				}
				$post = $redirect_posts[0];
			}

			// Taxonomy archives
			if($is_taxonomy || is_category() || is_tag()){
				$term = get_queried_object();
				$term_id = $term->term_id;

				// Check redirection is enabled
				$enable_redirect = get_term_meta($term_id, '_siteseo_redirections_enabled', true);

				if(empty($enable_redirect)){
					return;
				}

				$login_status = get_term_meta($term_id, '_siteseo_redirections_logged_status', true);
				$redirect_type = get_term_meta($term_id, '_siteseo_redirections_type', true);
				$redirect_url = get_term_meta($term_id, '_siteseo_redirections_value', true);
				$param_handling = get_term_meta($term_id, '_siteseo_redirections_param', true);
			}
			// Singular posts, pages, and products
			else{
				$enable_redirect = get_post_meta($post->ID, '_siteseo_redirections_enabled', true);

				if(empty($enable_redirect)){
					return;
				}

				$login_status = get_post_meta($post->ID, '_siteseo_redirections_logged_status', true);
				$redirect_type = get_post_meta($post->ID, '_siteseo_redirections_type', true);
				$redirect_url = get_post_meta($post->ID, '_siteseo_redirections_value', true);
				$param_handling = get_post_meta($post->ID, '_siteseo_redirections_param', true);
			}

			if($login_status === 'only_logged_in' && !is_user_logged_in()){
				return;
			}

			if($login_status === 'only_not_logged_in' && is_user_logged_in()){
				return;
			}

			if(!empty($redirect_url)){
				$final_url = $redirect_url;
				
				if(is_404() && !empty($_SERVER['QUERY_STRING'])){
					switch($param_handling){
						case 'exact_match':
							$current_params = sanitize_text_field(wp_unslash($_SERVER['QUERY_STRING']));
							$redirect_params = wp_parse_url($redirect_url, PHP_URL_QUERY);
							if($current_params !== $redirect_params){
								return;
							}
							break;
							
						case 'without_param':
							$final_url = strtok($redirect_url, '?');
							break;
							
						case 'with_ignored_param':
							$query_string = sanitize_text_field(wp_unslash($_SERVER['QUERY_STRING']));
							$final_url = $redirect_url;
							if(!empty($query_string)){
								$final_url .= (strpos($redirect_url, '?') !== false ? '&' : '?') . $query_string;
							}
							break;
					}
				}

				$status_code = !empty($redirect_type) ? intval($redirect_type) : 301;
				
				if(in_array($status_code, [410, 451]) && is_404()){
					status_header($status_code);
					nocache_headers();
					include(get_query_template('404'));
					exit;
				}

				wp_redirect($final_url, $status_code);
				exit;
			}
		}
	}
}
generatesitemap.php000064400000061701151526415240010444 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class GenerateSitemap{
	
	private static $paged = 1;

	static function settings(){
		global $siteseo;

		if(empty($siteseo->setting_enabled['toggle-xml-sitemap'])){
			return;	
		}
		
		if(!empty($siteseo->sitemap_settings['xml_sitemap_html_enable'])){
			add_shortcode('siteseo_html_sitemap', '\SiteSEO\GenerateSitemap::html_sitemap');
		}

		if(!empty($siteseo->sitemap_settings['xml_sitemap_general_enable'])){
			self::xml_sitemap();
		}
	}

	static function xml_sitemap(){
		add_filter('query_vars', function($vars){
			$vars[] = 'sitemap_type';
			$vars[] = 'paged';
			$vars[] = 'sitemap-stylesheet';
			return $vars;
		});
	}

	static function add_rewrite_rules(){
		global $siteseo;
		
		add_rewrite_rule('^sitemaps\.xsl$', 'index.php?sitemap-stylesheet=sitemap', 'top');
		add_rewrite_rule('^sitemaps\.xml$', 'index.php?sitemap_type=general', 'top');
		add_rewrite_rule('^author.xml$', 'index.php?sitemap_type=author', 'top');
		add_rewrite_rule('^media-sitemap([0-9]+)?.xml$', 'index.php?sitemap_type=media&paged=$matches[1]', 'top');
		add_rewrite_rule('^news([0-9]+)?.xml$', 'index.php?sitemap_type=news&paged=$matches[1]', 'top');
		add_rewrite_rule('^video-sitemap([0-9]+)?.xml$', 'index.php?sitemap_type=video&paged=$matches[1]', 'top');
		
		if(isset($siteseo->sitemap_settings['xml_sitemap_post_types_list'])){
            foreach($siteseo->sitemap_settings['xml_sitemap_post_types_list'] as $post_type => $settings){
                if(!empty($settings['include'])){
                    add_rewrite_rule('^'.$post_type.'-sitemap([0-9]+)?\.xml$', 'index.php?sitemap_type='.$post_type.'&paged=$matches[1]', 'top');
                }
            }
        }

        if(isset($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'])){
            foreach($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'] as $taxonomy => $settings){
                if(!empty($settings['include'])){
                    add_rewrite_rule('^'.$taxonomy.'-sitemap([0-9]+)?\.xml$', 'index.php?sitemap_type='.$taxonomy.'&paged=$matches[1]', 'top');
                }
            }
        }

		flush_rewrite_rules();
    }


	static function handle_sitemap_requests(){
		global $siteseo;

		$pro_settings = isset($siteseo->pro) ? $siteseo->pro : '';
		self::maybe_redirect();

		// Output the Sitemap style
		if(get_query_var('sitemap-stylesheet') === 'sitemap'){
			self::sitemap_xsl();
			exit;
		}
		
		if(get_query_var('paged')){
			self::$paged = get_query_var('paged');
		}
		
		$type = get_query_var('sitemap_type');
		if(!empty($type)){
			
			if($type === 'news' && !empty($pro_settings['google_news']) && !empty($pro_settings['toggle_state_google_news'])){
				
				self::generate_google_news_sitemap();
				exit;
			}
			
			if($type === 'video' && !empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap'])){
				self::generate_video_sitemap();
				exit;
			}

			// Custom post type
			if(isset($siteseo->sitemap_settings['xml_sitemap_post_types_list'][$type]) && !empty($siteseo->sitemap_settings['xml_sitemap_post_types_list'][$type]['include'])){
				self::generateSitemap($type);
				exit;
			}

			//custom taxomies type
			if(isset($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'][$type]) && !empty($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'][$type]['include'])){
				self::generate_term_sitemap($type);
				exit;
			}
 
			switch($type){
				case 'general':
					self::generate_index_sitemap();
					break;
				case 'post':
					self::generateSitemap('post');
					break;
				case 'page':
					self::generateSitemap('page');
					break;
				case 'category':
					self::generate_term_sitemap('category');
					break;
				case 'post_tag':
					self::generate_term_sitemap('post_tag');
					break;
				case 'author':
					self::generate_author_sitemap();
					break;
				case 'news':
					self::generate_google_news_sitemap();
					break;
				case 'video':
					self::generate_video_sitemap();
					break;
				default:
					wp_die(esc_html__('Invalid sitemap type.', 'siteseo'));
 			}
 		}
	}
	
	static function generate_index_sitemap(){
		global $siteseo;
		
		$pro_settings = isset($siteseo->pro) ? $siteseo->pro : '';

		header('Content-Type: application/xml; charset=UTF-8');
		
		if(get_option('permalink_structure')){
			$xsl_url = home_url('/sitemaps.xsl');
		} else {
			$xsl_url = home_url('/?sitemaps-stylesheet=sitemap');
		}

		echo '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="' . esc_url($xsl_url) . '" ?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

		// Post types
		if(isset($siteseo->sitemap_settings['xml_sitemap_post_types_list'])){
			foreach($siteseo->sitemap_settings['xml_sitemap_post_types_list'] as $post_type => $settings){
				$posts = get_posts(
					[
						'post_type' => $post_type,
						'fields'=> 'ids',
						'numberposts' => -1,
						'post_status' => 'publish',
						'has_password' => false,
						'no_found_rows' => true,
						'ignore_sticky_posts' => true,
						'update_post_term_cache' => false,
					]
				);

				if(empty($posts)){
					continue;
				}

				$total_pages = (int) ceil(count($posts) / 1000);

				if(!empty($settings['include']) && !empty($total_pages)){
					$last_post = get_posts([
						'post_type' => $post_type,
						'numberposts' => 1,
						'post_status' => 'publish',
						'orderby' => 'modified',
						'order' => 'DESC',
						'fields' => 'ids',
					]);
					
					$lastmod = !empty($last_post) ? get_post_modified_time('c', true, $last_post[0]) : current_time('c');
					
					for($page = 1; $page <= $total_pages; $page++){					
						echo '<sitemap>
							<loc>'.esc_url(home_url("/$post_type-sitemap$page.xml")).'</loc>
							<lastmod>'.esc_xml($lastmod).'</lastmod>
						</sitemap>';
					}
				}
			}
		}

		// Taxonomies
		if(isset($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'])){
			foreach($siteseo->sitemap_settings['xml_sitemap_taxonomies_list'] as $taxonomy => $settings){
				
				$args = [
					'taxonomy' => $taxonomy,
					'hide_empty' => true,
					'fields' => 'count',
					'hierarchical' => false,
					'update_term_meta_cache' => false,
				];
				
				$tax_count = get_terms($args);

				if(is_wp_error($tax_count) || $tax_count == 0){
					continue;
				}

				$total_pages = (int) ceil($tax_count/2000);
				
				if(!empty($settings['include']) && $total_pages > 0){
					$terms = get_terms([
						'taxonomy' => $taxonomy,
						'number' => 1,
						'orderby' => 'term_order',
						'order' => 'DESC',
						'fields' => 'ids',
					]);
					
					$lastmod = !empty($terms) ? current_time('c') : current_time('c'); // taxonomy terms don't have modified, fallback
					
					for($page = 1; $page <= $total_pages; $page++){
						echo '<sitemap>	
							<loc>'.esc_url(home_url("/$taxonomy-sitemap$page.xml")).'</loc>
							<lastmod>'.esc_xml($lastmod).'</lastmod>
						</sitemap>';
					}
				}
			}
		}

		// Author
		if(!empty($siteseo->sitemap_settings['xml_sitemap_author_enable'])){
			echo '<sitemap>
				<loc>'.esc_url(home_url('/author.xml')).'</loc>
				<lastmod>'.esc_xml(current_time('c')).'</lastmod>
			</sitemap>';
		}
		
		// Google News
		if(!empty($pro_settings['google_news']) && !empty($pro_settings['toggle_state_google_news'])){
			echo '<sitemap>
				<loc>'.esc_url(home_url('/news.xml')).'</loc>
				<lastmod>'.esc_xml(current_time('c')).'</lastmod>
			</sitemap>';
		}
		
		// Video
		if(!empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap'])){
			$video_posts = get_posts([
				'post_type' => $pro_settings['video_sitemap_posts'],
				'fields' => 'ids',
				'numberposts' => 1,
				'orderby' => 'modified',
				'order' => 'DESC',
				'fields' => 'ids',
				'meta_query' => [
					[
						'key' => '_siteseo_video_disabled',
						'compare' => 'NOT EXISTS'
					]
				]
			]);
				
				
			$lastmod = !empty($video_posts) ? get_post_modified_time('c', true, $video_posts[0]) : current_time('c');
			
				for($page = 1; $page <= $total_pages; $page++){
					echo '<sitemap>
						<loc>'.esc_url(home_url("/video-sitemap$page.xml")).'</loc>
						<lastmod>'.esc_xml($lastmod).'</lastmod>
					</sitemap>';
				}

		}
		
		echo '</sitemapindex>';
		exit;
	}

	// post
	static function generate_post_sitemap(){
		self::generateSitemap('post');
	}

	// page
	static function generate_page_sitemap(){
		self::generateSitemap('page');
	}

	// category 
	static function generate_category_sitemap(){
		self::generate_term_sitemap('category');
	}

	//post tag
	static function generate_post_tag_sitemap(){
		self::generate_term_sitemap('post_tag');
	}

	// taxonomy
	static function generate_taxonomy_sitemap(){
		self::generate_term_sitemap('taxonomy');
	}

	// google news pro feature
	static function generate_google_news_sitemap(){
		
		if(class_exists('\SiteSEOPro\GoogleNews') && method_exists('\SiteSEOPro\GoogleNews', 'google_news_sitemap')){
			\SiteSEOPro\GoogleNews::google_news_sitemap();
		}
	}
	
	// video sitemap pro feature
	static function generate_video_sitemap(){
		if(class_exists('\SiteSEOPro\VideoSitemap') && method_exists('\SiteSEOPro\VideoSitemap', 'render_sitemap')){
			\SiteSEOPro\VideoSitemap::render_sitemap();
		}
	}

	static function generateSitemap($post_type){
		global $siteseo;
		
		header('Content-Type: application/xml; charset=utf-8');
		
		$offset = (1000*(self::$paged - 1));

		$posts = get_posts(
		[
			'post_type' => $post_type,
			'post_status' => 'publish',
			'numberposts' => 1000,
			'offset' => $offset,
			'order' => 'DESC',
			'orderby' => 'modified',
			'has_password' => false,
			'no_found_rows' => true,
			'lang' => 'all',
			'meta_query' => [
			[
				'key' => '_siteseo_robots_index',
				'compare' => 'NOT EXISTS'
			]]
		]);

		if(get_option('permalink_structure')){
			$xsl_url = home_url('/sitemaps.xsl');
		} else {
			$xsl_url = home_url('/?sitemaps-stylesheet=sitemap');
		}

		echo '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="' . esc_url($xsl_url) . '" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" '.((!empty($siteseo->sitemap_settings['xml_sitemap_img_enable'])) ? 'xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"' : '').'>';

		if(self::$paged == 1){
			if(get_option('show_on_front') === 'page' && get_option('page_on_front')){
				echo "\t".'<url>
				<loc>'.esc_url(trailingslashit(home_url())).'</loc>
				<lastmod>'.esc_html(get_the_modified_date('c', get_option('page_on_front'))).'</lastmod>
				</url>';
			} else{
				echo "\t".'<url>
				<loc>'.esc_url(trailingslashit(home_url())).'</loc>
				</url>';
			}
		}

		foreach($posts as $post){
				
			if($post->ID == get_option('page_on_front')){
				continue;
			}
			
			$image_xml = '';
			if(!empty($siteseo->sitemap_settings['xml_sitemap_img_enable'])){
				$images = self::get_page_images($post);
				if(!empty($images)){
					foreach($images as $image){
						$image_xml .= "<image:image>\n";
						$image_xml .= "\t\t\t<image:loc>".esc_url($image)."</image:loc>\n";
						$image_xml .= "\t\t</image:image>";
					}
				}
			}

			echo "\t<url>
				<loc>".esc_url(get_permalink($post->ID))."</loc>
				<lastmod>".esc_html(get_the_modified_date('c', $post->ID))."</lastmod>
				".$image_xml."
			</url>";
		}

		echo '</urlset>';
		exit;
	}

	static function generate_term_sitemap($taxonomy){
		header('Content-Type: application/xml; charset=utf-8');
		
		$offset = (2000*(self::$paged - 1));

		if(get_option('permalink_structure')){
			$xsl_url = home_url('/sitemaps.xsl');
		} else {
			$xsl_url = home_url('/?sitemaps-stylesheet=sitemap');
		}

		echo '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="' . esc_url($xsl_url) . '" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
		$terms = get_terms([
			'taxonomy' => $taxonomy,
			'hide_empty' => false,
			'number' => 2000,
			'offset' => $offset,
			'hierarchical' => false,
			'update_term_meta_cache' => false,
			'lang' => 'all',
			'meta_query' => [
			[
				'key' => '_siteseo_robots_index',
				'compare' => 'NOT EXISTS'
			]]
		]);

		foreach($terms as $term){
			
			// most recent post in this term to determine lastmod date
			$recent_posts = get_posts([
				'tax_query' => [
					[
						'taxonomy' => $taxonomy,
						'field' => 'term_id',
						'terms' => $term->term_id,
					]
				],
				'numberposts' => 1,
				'orderby' => 'modified',
				'order' => 'DESC',
				'post_status' => 'publish'
			]);

			$last_mod = '';
			if(!empty($recent_posts)){
				$last_mod = "\n\t\t".'<lastmod>'.esc_html(get_the_modified_date('c', $recent_posts[0]->ID)).'</lastmod>';
			}
			
			echo "\t". '<url>
			<loc>'.esc_url(get_term_link($term)).'</loc>'.$last_mod.'
			</url>';
		}

		echo '</urlset>';
		exit;
	}

	static function generate_author_sitemap(){
		header('Content-Type: application/xml; charset=utf-8');

		if(get_option('permalink_structure')){
			$xsl_url = home_url('/sitemaps.xsl');
		} else {
			$xsl_url = home_url('/?sitemaps-stylesheet=sitemap');
		}

		echo '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="' . esc_url($xsl_url) . '" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

		// Fetch all authors
 		$authors = get_users(
			['capability' => ['publish_posts']]
		);

		foreach($authors as $author){
			// get the last modified date of the author's most recent post
			$last_post = get_posts([
				'author' => $author->ID,
				'numberposts' => 1,
				'orderby' => 'modified',
				'order' => 'DESC',
				'post_status' => 'publish'
			]);
			
			$lastmod_date = '';
			if(!empty($last_post)){
				$lastmod_date = get_the_modified_date('c', $last_post[0]->ID);
			} else{
				// user registration date if no posts
				$lastmod_date = gmdate('c', strtotime($author->user_registered));
			}

			echo "\t".'<url>
			<loc>'.esc_url(get_author_posts_url($author->ID)).'</loc>
			<lastmod>'.esc_html($lastmod_date).'</lastmod>
		</url>';
		}

		echo '</urlset>';
		exit;
	}

	static function html_sitemap($atts = []){
		global $siteseo;

		$atts = shortcode_atts(
			[
				'cpt' => '', // Default
			],
			$atts,
			'siteseo_html_sitemap'
		);

		$disable_date = !empty($siteseo->sitemap_settings['xml_sitemap_html_date']);
		$order_by = !empty($siteseo->sitemap_settings['xml_sitemap_html_orderby']) ? $siteseo->sitemap_settings['xml_sitemap_html_orderby']  : 'date';
		$order = !empty($siteseo->sitemap_settings['xml_sitemap_html_order']) ? $siteseo->sitemap_settings['xml_sitemap_html_order'] : 'DESC';		
		$exclude_string = isset($siteseo->sitemap_settings['xml_sitemap_html_exclude']) ? $siteseo->sitemap_settings['xml_sitemap_html_exclude'] : '';
		$exclude_pages = [];
		if(!empty($exclude_string)){
			$exclude_pages = array_map('trim', explode(',', $exclude_string));
		}

		$output = '';

		if($order !== 'ASC' && $order !== 'DESC'){
			$order = 'DESC';
		}

		$orderby_map = [
			'post_title' => 'title',
			'modified_date' => 'modified',
			'post_id' => 'ID',
			'menu_order' => 'menu_order',
			'date' => 'date', // Default
		];

		$orderby = !empty($orderby_map[$order_by]) ? $orderby_map[$order_by] : 'date';
		$cpt_list = !empty($atts['cpt']) ? explode(',', $atts['cpt']) : [];

		if(!empty($siteseo->sitemap_settings['xml_sitemap_post_types_list'])){ 
			foreach($siteseo->sitemap_settings['xml_sitemap_post_types_list'] as $post_type => $settings){
				if(!empty($settings['include']) && (empty($cpt_list) || in_array($post_type, $cpt_list))){

					$output .= '<h2>'.esc_html(ucfirst($post_type)).'</h2>';

					$args = [
						'post_type' => $post_type,
						'post_status' => 'publish',
						'numberposts' => -1,
						'orderby' => $orderby,
						'order' => $order,
					];

					$posts = get_posts($args);

					if(!empty($posts)){
						$output .= '<ul>';
						foreach($posts as $post){
							if(in_array($post->ID, $exclude_pages)){
								continue;
							}

							$post_title = get_the_title($post->ID) ?: $post->ID;

							$output .= '<li><a href="'.esc_url(get_permalink($post->ID)).'">'.esc_html($post_title).'</a>';

							if(!$disable_date){
								$output .= '<span class="post-date"> - '.esc_html(get_the_modified_date('j F Y', $post->ID)).'</span>';
							}

							$output .= '</li>';
						}
						$output .= '</ul>';
					}else{
						$output .= '';
					}
				}
			}
		}

		return $output;
	}
	
	static function sitemap_xsl(){
		global $siteseo;
		
		$pro_settings = isset($siteseo->pro) ? $siteseo->pro : '';
		$title = __('XML Sitemap', 'siteseo');
		$generated_by = __('Generated by SiteSEO', 'siteseo');
		$sitemap_index_txt = __('This XML Sitemap Index file contains', 'siteseo');
		$sitemap_count_txt = __('This XML Sitemap contains', 'siteseo');
		$image_count_txt = __('Images', 'siteseo');
		$last_modified_txt = __('Last Modified', 'siteseo');
		$index_sitemap_url = home_url('/sitemaps.xml');
		
		$image_sitemap_enabled = !empty($siteseo->sitemap_settings['xml_sitemap_img_enable']) ? true : false; 
		$video_sitemap_enabled = !empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap']) ? true : false;
		
		header('Content-Type: application/xml; charset=UTF-8');

		echo '<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
	xmlns:html="http://www.w3.org/TR/REC-html40"
	xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"';
	
	if(!empty($pro_settings['toggle_state_google_news']) && !empty($pro_settings['google_news'])){
		echo "\t" .'xmlns:news="https://www.google.com/schemas/sitemap-news/0.9/"';
	}
    
	if(!empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap'])){
			echo "\t" .'xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"';
    	}
    
	echo "\t" .'xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
	<xsl:template match="/">
		<html xmlns="http://www.w3.org/1999/xhtml">
			<head>
				<title>'.esc_xml($title).'</title>
				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
				<style>
					* {
						box-sizing: border-box;
					}
					body{
						font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
						background-color: #f0f2f5;
						margin: 0;
						padding: 0;
						overflow-x: hidden;
					}
					header{
						background: linear-gradient(135deg, #022448, #034f84);
						padding: 20px;
						color: #ffffff;
						text-align: center;
						width: 100%;
						margin-bottom:15px;
					}
					header h1{
						font-size: 32px;
						margin: 0;
					}
					header p{
						margin: 5px 0 0;
						font-size: 16px;
						text-decoration: underline;
					}
					header .siteseo-index-link a{
						color: #ffffff;
						text-decoration: none;
					}
					header .siteseo-index-link a:hover{
						text-decoration: underline;
					}
					.siteseo-sitemap-container{
						width: 60%;
						margin: 0 auto;
						margin-bottom: 10px;
					}
					.siteseo-sitemap-container a{
						color:#007bff;
						text-decoration: none;
					}

					.siteseo-sitemap-table-wrap{
						background-color: #ffffff;
						box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
						border-radius: 8px;
						margin-top:10px;
						overflow:auto;
					}

					table{
						width: 100%;
						border-collapse: collapse;
					}
					table thead tr{
						background-color: #034f84;
						color: #ffffff;
					}
					table th, table td{
						padding: 10px;
						text-align: left;
					}
					table tbody tr:nth-child(even){
						background-color: #f9f9f9;
					}
					.siteseo-video-thumbnail{
					        max-width: 160px;
					        max-height: 120px;
					        border-radius: 4px;
					}
					.siteseo-video-info{
						margin-left: 15px;
					}
					.siteseo-video-container{
						display: flex;
						align-items: center;
						margin: 10px 0;
					}
					.siteseo-video-title{
						font-weight: bold;
						margin-bottom: 5px;
					}
					.siteseo-video-description{
						color: #555;
						font-size: 14px;
						margin-bottom: 5px;
					}
					.siteseo-video-meta{
						font-size: 13px;
						color: #777;
					}
					.siteseo-video-url{
						word-break: break-all;
						font-size: 13px;
						color: #007bff;
					}
				</style>
			</head>
			<body>
				<header>
					<h1>'.esc_xml($title).'</h1>
					<span>'.esc_xml($generated_by).'</span>
					<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &gt; 0">
						<div class="siteseo-description" style="text-align:center;">'.esc_xml($sitemap_index_txt).' <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps</div>
					</xsl:if>
					
					<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
						<div class="siteseo-description" style="text-align:center;">'.esc_xml($sitemap_count_txt).' <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs</div>
					</xsl:if>
				</header>
				<div class="siteseo-sitemap-container">
					<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
					<a href="'.esc_url($index_sitemap_url).'">Index Sitemap</a>
					</xsl:if>
					<div class="siteseo-sitemap-table-wrap">
						<table>
						<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &gt; 0">
						<thead>
							<tr>
								<th>URL</th>
								<th>Last Modified</th>
							</tr>
						</thead>
						<tbody>
							<xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
								<tr>
									<td><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc"/></a></td>
									<td>
										<xsl:value-of select="sitemap:lastmod"/>
										<xsl:if test="not(sitemap:lastmod)">-</xsl:if>
									</td>
								</tr>
							</xsl:for-each>
						</tbody>
						</xsl:if>
						
						<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">';
						
						if($video_sitemap_enabled && class_exists('\SiteSEOPro\VideoSitemap') && method_exists('\SiteSEOPro\VideoSitemap', 'render_video_xsl')){
							 echo'<xsl:if test="sitemap:urlset/sitemap:url/video:video">'
									. \SiteSEOPro\VideoSitemap::render_video_xsl() .
								'</xsl:if>
								<xsl:if test="not(sitemap:urlset/sitemap:url/video:video)">
									<thead>
										<tr>
											<th>URL</th>';
											if(!empty($image_sitemap_enabled)){
												echo'<th>'.esc_xml($image_count_txt).'</th>';
											}
											
										echo'<th>'.esc_xml($last_modified_txt).'</th>
										</tr>
									</thead>
									<tbody>
										<xsl:for-each select="sitemap:urlset/sitemap:url">
											<tr>
												<td><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc"/></a></td>';
												
												if(!empty($image_sitemap_enabled)){
													echo'<td>
														<xsl:value-of select="count(image:image)"/>
													</td>';
												}
												
												echo'<td><xsl:value-of select="sitemap:lastmod"/></td>
											</tr>
										</xsl:for-each>
									</tbody>
								</xsl:if>';
						} else {
							echo'<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
								<thead>
									<tr>
										<th>URL</th>';
										
										if(!empty($image_sitemap_enabled)){
											echo'<th>'.esc_xml($image_count_txt).'</th>';
										}
										
										echo'<th>'.esc_xml($last_modified_txt).'</th>
									</tr>
								</thead>
								<tbody>
									<xsl:for-each select="sitemap:urlset/sitemap:url">
										<tr>
											<td><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc"/></a></td>';
											
											if(!empty($image_sitemap_enabled)){
												echo'<td>
													<xsl:value-of select="count(image:image)"/>
												</td>';
											}
											
											echo'<td><xsl:value-of select="sitemap:lastmod"/></td>
										</tr>
									</xsl:for-each>
								</tbody>
							  </xsl:if>';
						}
						
						echo'</xsl:if>
						</table>
					</div>
				</div>
			</body>
		</html>

</xsl:template>
</xsl:stylesheet>';
	}
	
	static function get_page_images($post){

		$images = [];
		$thumb = get_the_post_thumbnail_url($post->ID);
		
		if(!empty($thumb)){
			$images[] = $thumb;
		}
		
		if(!class_exists('DOMDocument') || empty($post->post_content)){
			return $images;
		}

		libxml_use_internal_errors(true);
		
		$dom = new \DOMDocument();
		
		$dom->loadHTML('<?xml encoding="utf-8" ?>' . $post->post_content);
		$dom->preserveWhiteSpace = false;

		libxml_clear_errors();
		
		$img_tags = $dom->getElementsByTagName('img');
		
		if(empty($img_tags)){
			return;
		}
		
		foreach($img_tags as $img_tag){
			$url = $img_tag->getAttribute('src');

			if(empty($url)){
				continue;
			}

			$url = sanitize_url($url);
			
			// The Image has some different URL which means it does not belongs to our site.
			if(strpos($url, untrailingslashit(home_url())) === FALSE){
				continue;
			}
			
			$images[] = $url;
		}

		return $images;
	}

	static function maybe_redirect(){
		global $wp;

		if(empty($wp) || empty($wp->request)){
			return;
		}
		
		$redirects = ['sitemap.xml', 'wp-sitemap.xml', 'sitemap_index.xml'];

		if(in_array($wp->request, $redirects)){
			wp_safe_redirect(home_url('sitemaps.xml'), 301);
			die();
		}
	}
	
}
columns.php000064400000012237151526415240006747 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Columns{

	static function add_columns($colums){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return $colums;  // toggle disable
		}

		$options = $siteseo->advanced_settings;
		
		if(!empty($options['appearance_title_col'])){
			$colums['seo_title'] = __('Title tag', 'siteseo');
		}
		
		if(!empty($options['appearance_meta_desc_col'])){
			$colums['meta_description'] = __('Meta Desc' , 'siteseo');
		}
		
		if(!empty($options['appearance_redirect_enable_col'])){
			$colums['redirect_enabled'] = __('Redirect?', 'siteseo');
		}
		
		if(!empty($options['appearance_redirect_url_col'])){
			$colums['redirect_url'] = __('Redirect URL', 'siteseo');
		}
		
		if(!empty($options['appearance_canonical'])){
			$colums['canonical_url'] = __('Canonical', 'siteseo');
		}
		
		if(!empty($options['appearance_target_kw_col'])){
			$colums['target_keyword'] = __('Target Kw', 'siteseo');
		}
		
		if(!empty($options['appearance_noindex_col'])){
			$colums['noindex'] = __('noindex?', 'siteseo');
		}
		
		if(!empty($options['appearance_nofollow_col'])){
			$colums['nofollow'] = __('nofollow?', 'siteseo');
		}
		
		if(!empty($options['appearance_words_col'])){
			$colums['word_count'] = __('Words', 'siteseo');
		}
		
		if(!empty($options['appearance_score_col'])){
			$colums['seo_score'] = __('Score', 'siteseo');
		}
		
		return $colums;
	}
	
	static function populate_custom_seo_columns($column, $post_id){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return;  // toggle disable
		}
		
		$options = $siteseo->advanced_settings;

		switch($column){
			
			case 'seo_title':				
				if(!empty($options['appearance_title_col'])){
					$title = get_post_meta($post_id, '_siteseo_titles_title', true);
					echo esc_html(\SiteSEO\TitlesMetas::replace_variables($title));
				}
				break;

			case 'meta_description':
				if(!empty($options['appearance_meta_desc_col'])){
					$desc = get_post_meta($post_id, '_siteseo_titles_desc', true);
					$replaced_desc = \SiteSEO\TitlesMetas::replace_variables($desc);
					echo esc_html($replaced_desc);
				}
				break;

			case 'redirect_enabled':
				if(!empty($options['appearance_meta_desc_col'])){
					$redirect_enabled = get_post_meta($post_id, 'siteseo_redirections_enabled', true);
					echo $redirect_enabled ? esc_html__('Yes', 'siteseo') : esc_html__('No', 'siteseo');
				}
				break;
				
			case 'redirect_url':
				if(!empty($options['appearance_redirect_enable_col'])){
					echo esc_url(get_post_meta($post_id, '_siteseo_redirections_value', true));
				}
				break;

			case 'canonical_url':
				if(!empty($options['appearance_redirect_url_col'])){
					echo esc_url(get_post_meta($post_id, '_siteseo_robots_canonical', true));
				}
				break;

			case 'target_keyword':
				if(!empty($options['appearance_canonical'])){
					$keywords = esc_html(get_post_meta($post_id, '_siteseo_analysis_target_kw', true));
					echo !empty($keywords) ? esc_html($keywords) : '';
				}
				break;
				
			case 'noindex':
				if(!empty($options['appearance_noindex_col'])){
					$noindex = get_post_meta($post_id, '_siteseo_robots_index', true);
					echo $noindex ? esc_html__('Yes', 'siteseo') : esc_html__('No', 'siteseo');
				}
				break;

			case 'nofollow':
				if(!empty($options['appearance_nofollow_col'])){
					$nofollow = get_post_meta($post_id, '_siteseo_robots_follow', true);
					echo $nofollow ? esc_html__('Yes', 'siteseo') : esc_html__('No', 'siteseo');
				}
				break;

			case 'word_count':
				if(!empty($options['appearance_words_col'])){
					$content = get_post_field('post_content', $post_id);
					echo esc_html(str_word_count(wp_strip_all_tags($content)));
				}
				break;

			case 'seo_score':
				if(!empty($options['appearance_score_col'])){
					$score = get_post_meta($post_id, '_siteseo_score', true);
					echo !empty($score) ? esc_html($score) : '';
				}
				break;
		}
		
	}

	static function make_seo_columns_sortable($columns){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return $columns;  // toggle disable
		}
		
		$options = $siteseo->advanced_settings;
		
		if(!empty($options['appearance_title_col'])){
			$columns['seo_title'] = 'seo_title';
		}
		
		if(!empty($options['appearance_meta_desc_col'])){
			$columns['meta_description'] = 'meta_description';
		}
		
		if(!empty($options['appearance_target_kw_col'])){
			$columns['target_keyword'] = 'target_keyword';
		}
		
		if(!empty($options['appearance_words_col'])){
			$columns['word_count'] = 'word_count';
		}

		if(!empty($options['appearance_score_col'])){
			$columns['seo_score'] = 'seo_score';
		}

		return $columns;
		
	}
	
	static function hide_genesis_seo(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return; // toggle disable
		}
		
		$options = $siteseo->advanced_settings;

		if(!empty($options['appearance_genesis_seo_menu'])){
			remove_theme_support('genesis-seo-settings-menu');
		}
		
		if(!empty($options['appearance_genesis_seo_metaboxe'])){
			remove_action('admin_menu', 'genesis_add_inpost_seo_box');
		}
	}
}metaboxes/analysis.php000064400000156254151526415240011111 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Metaboxes;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Analysis{
	
	static function display_content_readibility($metabox_data){
		
		if(empty($metabox_data) || !isset($metabox_data['post_id'])){
			return; // Safeguard in case $metabox_data is incomplete or invalid.
		}

		$post_id = $metabox_data['post_id'];
		$readability_data = get_post_meta($post_id, '_siteseo_readibility_data', true);

		// Fetch and analyze readability data
		$analyzes = self::analyze_content($readability_data);

		// Render the readability data
		self::render_readibility($analyzes, $readability_data);
	}
	
	static function analyze_content($data){
		$analyzes = [];

		// Analyze different aspects
		$analyzes = self::analyze_power_word($analyzes, $data);
		$analyzes = self::analyze_title_number($analyzes, $data);
		$analyzes = self::analyze_passive_voice($analyzes, $data);
		$analyzes = self::analyze_paragraph_length($analyzes, $data);

		return $analyzes;
	}

	static function analyze_power_word($analyzes, $data){
		
		if(!empty($data['power_words'])){
			$analyzes['power_words'] = [
				'desc' => '<p>'.__('Good: You have power words in your title.', 'siteseo').'</p>',
				'impact' => 'good',
				'title'=>'Power Word in title'
			];
		} else{
			$analyzes['power_words'] = [
				'desc' => '<p>'.__('Consider adding power words to your title for better impact.', 'siteseo').'</p>',
				'impact' => 'low',
				'title'=> __('Power Word in title', 'siteseo')
			];
		}
		return $analyzes;
	}

	static function analyze_title_number($analyzes, $data){
		
		if(!empty($data['number_found'])){
			$analyzes['number_found'] = [
				/* translators: %s is the number found in the title */
				'desc' => '<p>'.sprintf(__('Good: Your title contains the number "%s".', 'siteseo'), $data['number_found']).'</p>',
				'impact' => 'good',
				'title' => 'Number in title'
			];
		} else{
			$analyzes['number_found'] = [
				'desc' => '<p>'.__('Consider adding a number to your title to improve CTR.', 'siteseo').'</p>',
				'impact' => 'low',
				'title' => 'Number in title'
			];
		}
		
		return $analyzes;
	}

	static function analyze_passive_voice($analyzes, $data){

		//$analyzes['title'] ='Passive Voice';
		if(empty($data['passive_voice'])){
			$analyzes['passive_voice'] = [
				'desc' => '<p>'.__('Great: No passive voice detected.', 'siteseo').'</p>',
				'impact' => 'good',
				'title' => 'Passive Voice'
			];
		} else {
		    $percentage = round(($data['passive_voice']['passive_sentences'] * 100) / $data['passive_voice']['total_sentences']);
		    if($percentage <= 10){
			$analyzes['passive_voice'] = [
				/* translators: %s is the number found in the title */
				'desc' => '<p>'.sprintf(__('Good: Only %s%% of sentences use passive voice.', 'siteseo'), $percentage).'</p>',
				'impact' => 'good',
				'title' => 'Passive Voice'
			];
		    } elseif($percentage < 20){
			$analyzes['passive_voice'] = [
				/* translators: %s is the percentage of sentences using passive voice */
				'desc' => '<p>'.sprintf(__('Okay: %s%% of sentences use passive voice. Try to reduce it.', 'siteseo'), $percentage).'</p>',
				'impact' => 'medium',
				'title' => 'Passive Voice'
			];
		    } else{
		        $analyzes['passive_voice'] = [
				/* translators: %s is the percentage of sentences using passive voice */
				'desc' => '<p>'.sprintf(__('High: %s%% of sentences use passive voice. Consider revising.', 'siteseo'), $percentage).'</p>',
				'impact' => 'high',
				'title' => 'Passive Voice'
		        ];
		    }
		}
		return $analyzes;
	}

	static function analyze_paragraph_length($analyzes, $data){

		if(empty($data['paragraph_length']) || $data['paragraph_length'] < 150){
		    $analyzes['paragraph_length'] = [
		        'desc' => '<p>Good: Your paragraphs are concise.</p>',
		        'impact' => 'good',
					'title' => 'Paragraph Length'
		    ];
		} else{
		    $analyzes['paragraph_length'] = [
			/* translators: %s is the current paragraph length in words */
		        'desc' => '<p>'.sprintf(__('Consider reducing paragraph length. Current length: %s words.', 'siteseo'), $data['paragraph_length']) . '</p>',
		        'impact' => 'low',
					'title' => 'Paragraph Length'
		    ];
		}
		return $analyzes;
	}

	static function render_readibility($analyzes, $analysis_data, $echo = true){
		$acceptable_svg = [
			'svg' => [
				'role' => true,
				'aria-hidden' => true,
				'focusable' => true,
				'width' => true,
				'height' => true,
				'viewbox' => true,
				'version' => true,
				'xmlns' => true,
				'fill' => true,
			],
			'path' => ['fill' => true, 'd' => true]
		];

		if(!empty($analyzes)){
			$order = ['1' => 'high', '2' => 'medium', '3' => 'low', '4' => 'good'];
			usort($analyzes, function ($a, $b) use ($order) {
				return array_search($a['impact'], $order) - array_search($b['impact'], $order);
			});

			// Define SVG icons
			$high_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>';
			$medium_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>';
			$good_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>';

			// Generate HTML
			$html = '<div id="siteseo-readibility-tabs">';
			foreach($analyzes as $key => $value){
				$impact_icon = '';
				switch ($value['impact']) {
					case 'high': $impact_icon = $high_icon; break;
					case 'medium': case 'low': $impact_icon = $medium_icon; break;
					case 'good': $impact_icon = $good_icon; break;
				}
				$html .= '<div class="siteseo-analysis-block">';
				$html .= '<div class="siteseo-analysis-block-title">';
				$html .= '<div><span class="impact ' . esc_attr($value['impact']) .'" aria-hidden="true">' . $impact_icon . '</span>' .
				/* translators: %s represents the degree of severity */
				'<span class="screen-reader-text">'. sprintf(esc_html__('Degree of severity: %s','siteseo'), esc_html($value['impact'])).'</span>' .
				esc_html($value['title']) . '</div>';
				$html .= '<span class="siteseo-arrow" aria-hidden="true"></span></div>';
				$html .= '<div class="siteseo-analysis-block-content">' . wp_kses_post($value['desc']) . '</div>';
				$html .= '</div>';
			}
			$html .= '</div>';
			
			if($echo){
				$allowed_html = array_merge(wp_kses_allowed_html('post'), $acceptable_svg);
				echo wp_kses($html, $allowed_html);
				return;
			}
			return $html;
		}
	}

	// Analaysis
	static function display_seo_analysis($post){
		$seo_analysis = self::perform_seo_analysis($post);
		
		echo '<div id="siteseo-analysis-tabs">
			<div id="siteseo-analysis-tabs-1">
				<div class="siteseo-analysis-summary">';
					if(!empty($seo_analysis)){
						// grp
						usort($seo_analysis['checks'], function ($a, $b) {
							$order = ['error' => 0, 'warning' => 1, 'good' => 2];
							
							$a_status_class = isset($a['status_class']) ? $a['status_class'] : '';
							$b_status_class = isset($b['status_class']) ? $b['status_class'] : '';
							
							$a_order = isset($order[$a_status_class]) ? $order[$a_status_class] : 3;
							$b_order = isset($order[$b_status_class]) ? $order[$b_status_class] : 3;
							
							return $a_order - $b_order;
						});

						echo '<div class="siteseo-analysis-summary-pill">';
							// counts logic
							if(!empty($seo_analysis['error_count'])){
								echo '<span><svg fill="#f33" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 22h-24l12-20z"/></svg>'.esc_html($seo_analysis['error_count']). ' Errors</span>';
							}
						
							if(!empty($seo_analysis['warning_count'])){
								echo '<span><svg xmlns="http://www.w3.org/2000/svg" fill="#fa3" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96z"/></svg>'.esc_html($seo_analysis['warning_count']). ' Warnings</span>';
							}
							
							if(!empty($seo_analysis['good_count'])){
								echo '<span><svg xmlns="http://www.w3.org/2000/svg" fill="#0c6" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg><span>'.esc_html($seo_analysis['good_count']). ' Good</span></span>';
							}
					
						echo '</div>
					</div><!-- .analysis-score -->';

				 // A triangle with exclamation in it.
				$medium_icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>';

				 // A check inside a solid circle
				$good_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>';
				
				$high_icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>';
				
				$allowed_svg_tags = ['svg' => ['xmlns' => true, 'viewbox' => true, 'width' => true, 'height' => true, 'class' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true], 'path' => ['d' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true]];

			   foreach($seo_analysis['checks'] as $check){

						echo '<div class="siteseo-analysis-block">';
							if(isset($check['label'])){
								echo'<div class="siteseo-analysis-block-title">';
									if(isset($check['status_class'])){
										$impact_icon = '';
										switch($check['status_class']){
											case 'good':
												$impact_icon = $good_icon;
												break;
											case 'warning':
												$impact_icon = $medium_icon_svg;
												break;
											case 'error':
												$impact_icon = $high_icon_svg;
												break;
										}

										echo '<div><span class="impact '.esc_attr($check['status_class']).'" aria-hidden="true">'.wp_kses($impact_icon, $allowed_svg_tags).'</span>
										
										<span class="screen-reader-text">'.
										/* translators: %s represents the degree of severity */
										sprintf(esc_html__('Degree of severity: %s','siteseo'), esc_html($check['status_class'])).'</span>';
									}

									echo esc_html($check['label']).'</div>
									<span class="siteseo-arrow" aria-hidden="true"></span>
								</div>';
							}
							if(isset($check['details'])){
								echo '<div class="siteseo-analysis-block-content" aria-hidden="true">'.wp_kses_post($check['details']).'</div>';
							}
						echo '</div><!-- .siteseo-analysis-block -->';
					}

				echo '</div><!-- #siteseo-analysis-tabs-1 -->
				</div><!-- #siteseo-analysis-tabs -->';
			}

	}

	static function perform_seo_analysis($post){
		
		$content = $post->post_content;
		$title = $post->post_title;
		$title = !empty(get_post_meta($post->ID, '_siteseo_titles_title',true)) ? get_post_meta($post->ID, '_siteseo_titles_title', true) : $title;
		$permalink = get_permalink($post->ID);
		$keywords = get_post_meta($post->ID, '_siteseo_analysis_target_kw', true);
		$meta_desc = get_post_meta($post->ID, '_siteseo_titles_desc', true);
		
		// Bricks
		if(defined('BRICKS_DB_PAGE_CONTENT')){
			$is_bricks_page = get_post_meta($post->ID, BRICKS_DB_PAGE_CONTENT, true);

			if(!empty($is_bricks_page) && is_array($is_bricks_page)){
				$content = self::get_bricks_page_content($is_bricks_page);
			}
		}
			
		if(empty($meta_desc)){
			$meta_desc = '';
		}

		$analysis = [
			'good_count' => 0,
			'warning_count' => 0,
			'error_count' => 0,
			'checks' => []
		];

		$canonical_check = self::check_canonical_url($permalink);
		$analysis['checks'][] = $canonical_check;
		self::update_analysis_score($analysis, $canonical_check);

		$word_count_check = self::check_word_count($content);
		$analysis['checks'][] = $word_count_check;
		self::update_analysis_score($analysis, $word_count_check);

		$keywords_density_check = self::check_keywords_density($content, $keywords);
		$analysis['checks'][] = $keywords_density_check;
		self::update_analysis_score($analysis, $keywords_density_check);

		$meta_title_check = self::check_meta_title($title);
		$analysis['checks'][] = $meta_title_check;
		self::update_analysis_score($analysis, $meta_title_check);

		$meta_description_check = self::check_meta_description($content, $meta_desc);
		$analysis['checks'][] = $meta_description_check;
		self::update_analysis_score($analysis, $meta_description_check);

		$image_alt_check = self::check_image_alt_texts($content);
		$analysis['checks'][] = $image_alt_check;
		self::update_analysis_score($analysis, $image_alt_check);

		$links_outbound_check = self::analyze_outbound_links($content);
		$analysis['checks'][] = $links_outbound_check;
		self::update_analysis_score($analysis, $links_outbound_check);

		$links_internal_check = self::analyze_internal_links($content);
		$analysis['checks'][] = $links_internal_check;
		self::update_analysis_score($analysis, $links_internal_check);

		$headings_check = self::check_headings($content);
		$analysis['checks'][] = $headings_check;
		self::update_analysis_score($analysis, $headings_check);

		$social_tags_check = self::check_social_meta_tags($post);
		$analysis['checks'][] = $social_tags_check;
		self::update_analysis_score($analysis, $social_tags_check);

		$structured_data_check = self::check_structured_data($post);
		$analysis['checks'][] = $structured_data_check;
		self::update_analysis_score($analysis, $structured_data_check);

		$permalink_keywords_check = self::check_keywords_in_permalink($permalink, $keywords);
		$analysis['checks'][] = $permalink_keywords_check;
		self::update_analysis_score($analysis, $permalink_keywords_check);

		$meta_robots_check = self::check_meta_robots($post);
		$analysis['checks'][] = $meta_robots_check;
		self::update_analysis_score($analysis, $meta_robots_check);

		$last_modified_check = self::check_last_modified_date($post);
		$analysis['checks'][] = $last_modified_check;
		self::update_analysis_score($analysis, $last_modified_check);

		$nofollow_links_check = self::analyze_nofollow_links($content);
		$analysis['checks'][] = $nofollow_links_check;
		self::update_analysis_score($analysis, $nofollow_links_check);
		
		$readability_data = [];
		$readability_data = self::analyze_readability($content, $title);
		update_post_meta($post->ID, '_siteseo_readibility_data', $readability_data);
		$analysis['checks'][] = $readability_data;

		return $analysis;
	}
	
	static function update_analysis_score(&$analysis, $check){
		switch($check['status']){
		    case 'Good':
		        $analysis['good_count']++;
		        break;
		    case 'Warning':
		        $analysis['warning_count']++;
		        break;
		    case 'Error':
		        $analysis['error_count']++;
		        break;
		}
	}
	
	static function check_canonical_url($permalink){
		$response = wp_remote_get($permalink);
		if(is_wp_error($response)){
			return [
				'label' => 'Canonical URL',
				'status' => 'Error',
				'status_class' => 'error',
				'details' => '<p>' . __('Unable to check canonical URL.', 'siteseo') . '</p>'
			];
		}
		
		$content = wp_remote_retrieve_body($response);
		
		preg_match_all('/<link[^>]+rel=[\'"](canonical)[\'"][^>]+href=[\'"]([^\'"]+)[\'"][^>]*>/i', $content, $matches);
		
		$canonical_urls = !empty($matches[2]) ? array_unique($matches[2]) : [];
		$count = count($canonical_urls);
		
		$details = '';
		$status = 'Warning';
		
		$details .= '<p>'. __('A canonical URL is required by search engines to handle duplicate content.', 'siteseo') .'</p>';
		
		if($count > 0){
			
			$details .= '<p>' .
			
			sprintf(
				/* translators: %s represents the degree of severity */
				_n(
					'We found %s canonical URL in your source code. Below, the list:',
					'We found %s canonical URLs in your source code. Below, the list:',
					$count,
					'siteseo'
				),
				number_format_i18n($count)
			) . '</p>';
			
			$details .= '<ul>';
			foreach($canonical_urls as $link){
				$details .= '<li>' .
					'<span class="dashicons dashicons-arrow-right"></span>' .
					'<a href="' . esc_url($link) . '" target="_blank">' . 
					esc_url($link) . 
					'</a>' .
					'<span class="dashicons dashicons-external"></span>' .
					'</li>';
			}
			$details .= '</ul>';
			
			if($count > 1){
				$status = 'Error';
				$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
					__('You must fix this. Canonical URL duplication is bad for SEO.', 'siteseo') . '</p>';
			} else{
				$status = 'Good';
			}
		} else{
			if(get_post_meta(get_the_ID(), '_siteseo_robots_index', true)){
				$status = 'Good';
				$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' . 
					__('This page doesn\'t have any canonical URL because your post is set to <strong>noindex</strong>. This is normal.', 'siteseo') . '</p>';
			} else{
				$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
					__('This page doesn\'t have any canonical URL.', 'siteseo') . '</p>';
			}
		}
		
		return [
			'label' => 'Canonical URL',
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}
	
	static function check_word_count($content){
		$word_count = str_word_count(wp_strip_all_tags($content));
		$unique_words = count(array_unique(str_word_count(wp_strip_all_tags($content), 1)));
		
		$details = '';
		
		if($word_count != 0){
			
			$details = '<p>'. __('Word count isn\'t a direct ranking factor, but it\'s important for your content to be high-quality, relevant, and unique. To meet these criteria, your article should include a sufficient number of paragraphs to ensure adequate word count.', 'siteseo') .'</p>';
		
			$details .= '<ul>';
			/* translators: %d represents the words found */
			$details .= '<li>'. sprintf(__('%d words found', 'siteseo'), $word_count) .'</li>';
			/* translators: %d represents the unique words found */
			$details .= '<li>'. sprintf(__('%d unique words found', 'siteseo'), $unique_words) .'</li>';
			$details .= '</ul>';
				
		}
		
		if($word_count == 0){
			$status = 'Error';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('No content? Try adding a few more paragraphs.!', 'siteseo') . '</p>';
		} elseif($word_count > 300){
			$status = 'Good';
			$details .= '<li><span class="dashicons dashicons-thumbs-up"></span>' . __('Your content contains over 300 words, which meets the minimum requirement for a post', 'siteseo') .'</li>';
		} else{
			$status = 'Error';
			$details .= '<li><span class="dashicons dashicons-thumbs-down"></span>' . __('Your content is too brief. Consider adding a few more paragraphs!', 'siteseo') .'</li>';
		}

		return [
			'label' => __('Word Count', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}

	static function check_keywords_density($content, $keywords){
		$content = mb_strtolower(wp_strip_all_tags($content), 'UTF-8');
		$keywords = array_filter(explode(',', trim($keywords)));
		$content_words = str_word_count($content, 1);
		$count_words = count($content_words);
		$details = '';

		if(empty($keywords) || empty($content_words)){
			$details .= '<p>' . __('We couldn\'t calculate the keyword density. This may be because you haven\'t added any content or your target keywords are missing from the post.', 'siteseo') . '</p>';
			
			return [
				'label' => __('Keyword Density', 'siteseo'),
				'status' => 'Error',
				'status_class' => 'error',
				'details' => $details
			];
		}

		// calulate
		$density_details = [];
		$all_density = [];
    
		foreach($keywords as $keyword){
			$keyword_occurrence = 0;

			$keyword = mb_strtolower(trim($keyword), 'UTF-8');

			$keyword_words = preg_split('/\s+/u', $keyword, -1, PREG_SPLIT_NO_EMPTY);
			$keyword_word_count = count($keyword_words);

			// Count occurrences
			if($keyword_word_count > 1){

				$pattern = '/' . preg_quote($keyword, '/') . '/iu';
				preg_match_all($pattern, $content, $matches);
				$keyword_occurrence = count($matches[0]);
			} else {
				$word_counts = array_count_values($content_words);
				$keyword_occurrence = isset($word_counts[$keyword]) ? $word_counts[$keyword] : 0;

			}

			// Calculate density
			if($count_words > 0){
				$kw_density = ($keyword_occurrence * $keyword_word_count * 100) / $count_words;
			} else {
				$kw_density = 0;
			}

			$all_density[] = number_format($kw_density, 2);
			
			$density_details[] = 
			/* translators: %s represents the degree of severity */ 
			sprintf(
				'<ul><li><span class="dashicons dashicons-arrow-right"></span>%s</li></ul>',
				sprintf(
					/* translators: %s represents a keyword density of */
					esc_html__('%1$s was found %2$d times in your content, a keyword density of %3$s%%', 'siteseo'),
					esc_html($keyword),
					$keyword_occurrence,
					number_format($kw_density, 2)
				)
			);
		}

		$details .= implode('', $density_details);

		$details .= '<p class="description">'.
			sprintf(
				__('Find out more about <a href="%s" target="_blank">keywords stuffing</a>', 'siteseo'),
				'https://www.youtube.com/watch?v=Rk4qgQdp2UA'
			) .
		'</p>';

		if(count($all_density) === 0){
			return [
				'label' => __('Keyword Density', 'siteseo'),
				'status' => 'Error',
				'status_class' => 'error',
				'details' => $details
			];
		}

		//avg density
		$avg_density = array_sum($all_density)/count($all_density);

		$status = ($avg_density > 1) ? 'Good' : 'Warning';

		return [
			'label' => __('Keyword Density', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}
	
	static function check_meta_title($title, $keywords = []){
		$details = '';
		$status = 'Good';
		$status_class = 'good';
		
		$title = \SiteSEO\TitlesMetas::replace_variables($title);

		// mb_strlen for correct UTF-8
		$title_length = mb_strlen($title, 'UTF-8');

		// length
		if(empty($title)){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
			__('A custom title has not been set for this post. If the global meta title works for you, you can disregard this recommendation.', 'siteseo') . '</p>';
			$status = 'Warning';
			$status_class = 'warning';
		} elseif($title_length > 60){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' .
			__('Your custom title is too lengthy.', 'siteseo') . '</p>';
			$status = 'Warning';
			$status_class = 'warning';
		} elseif($title_length >= 10 && $title_length <= 60){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' .
			__('The length of your title is appropriate.', 'siteseo') . '</p>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
			__('Your custom title is too short.', 'siteseo') . '</p>';
			$status = 'Warning';
			$status_class = 'warning';
			
		}

		if(!empty($keywords)){
			$keyword_counts = [];
			foreach($keywords as $kw_name){
				$kw_count = substr_count(strtolower($title), strtolower($kw_name));
				if($kw_count > 0){
					$keyword_counts[] = $kw_count;
					/* translators: %s represents the degree of severity */
					$details .= '<ul><li><span class="dashicons dashicons-arrow-right"></span>'. sprintf(esc_html__('%1$s was found %2$d times.', 'siteseo'), $kw_name, $kw_count) . '</li></ul>';
				}
			}

			if(!empty($keyword_counts)){
				$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'.__('The target keywords are included in the Meta Title', 'siteseo').'</p>';
			} else {
				$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'.__('None of your target keywords are present in the Meta Title.', 'siteseo').'</p>';
				$status = $status === 'Good' ? 'Warning' : $status;
				$status_class = $status_class === 'good' ? 'warning' : $status_class;
			}
		}

		return [
			'label' => __('Meta Title', 'siteseo'),
			'status' => $status,
			'status_class' => $status_class,
			'details' => $details
		];
	}

	static function check_meta_description($content, $meta_description = '', $keywords = []){
		$details = '';
		$status = 'Good';
		$status_class = 'good';

		$desc = !empty($meta_description) ? $meta_description : wp_trim_words($content, 20);
		$description = \SiteSEO\TitlesMetas::replace_variables($desc);

		// UTF-8
		$description_length = mb_strlen($description, 'UTF-8');

		// desc length
		if(empty($meta_description)){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
				__('A custom meta description has not been set for this post. If the global meta description works for you, you can ignore this recommendation.', 'siteseo') . '</p>';
				
			$status = 'Warning';
			$status_class = 'warning';
		} elseif($description_length > 160){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('Your custom meta description is too lengthy', 'siteseo') .'</p>';
			$status = 'Warning';
			$status_class = 'warning';
		} elseif($description_length >= 50 && $description_length <= 160){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('The length of your meta description is appropriate.', 'siteseo').'</p>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('The description has been set properly.', 'siteseo').'</p>';
		}

		if(!empty($keywords)){
			$keyword_counts = [];
			foreach($keywords as $kw_name){
				$kw_count = substr_count(strtolower($description), strtolower($kw_name));
				if($kw_count > 0){
					$keyword_counts[] = $kw_count;
					$details .= '<li><span class="dashicons dashicons-arrow-right"></span>' . 
						/* translators: %s represents the key word count */
						sprintf(esc_html__('%1$s was found %2$d times.', 'siteseo'), $kw_name, $kw_count) . '</li>';
				}
			}

			if(!empty($keyword_counts)){
				$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('The target keywords are included in the Meta description.', 'siteseo') . '</p>';
			} else{
				$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('None of your target keywords are included in the Meta description.', 'siteseo') . '</p>';
				$status = $status === 'Good' ? 'Warning' : $status;
				$status_class = $status_class === 'good' ? 'warning' : $status_class;
			}
		}

		return [
			'label' => 'Meta Description',
			'status' => $status,
			'status_class' => $status_class,
			'details' => $details
		];
	}
	
	static function check_image_alt_texts($content){

			$result = [
				'label' => __('Alternative texts of images', 'siteseo'),
				'status' => 'Good',
				'status_class' => 'good',
				'details' => ''
			];

			if(empty($content)){
				$result['status'] = 'Warning';
				$result['status_class'] = 'warning';
				$result['details'] = '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
					__('No content found to analyze. Please add some content to check for images and alt texts.', 'siteseo') . '</p>';
				return $result;
			}

			preg_match_all('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]*>/i', $content, $image_matches);
			preg_match_all('/<img[^>]+alt=[\'"]([^\'"]+)[\'"][^>]*>/i', $content, $alt_matches);

			$images_count = count($image_matches[0]);
			$alt_text_count = count(array_filter($alt_matches[1], 'strlen'));

			if($images_count === 0){
				$result['status'] = 'Warning';
				$result['status_class'] = 'warning';
				$result['details'] = '<p><span class="dashicons dashicons-thumbs-down"></span>' .
					__('We couldn\'t find any images in your content. Adding media can boost your SEO.', 'siteseo') . '</p>';
				return $result;
			}

			if($images_count !== $alt_text_count){
				$result['status'] = ($alt_text_count > 0) ? 'Warning' : 'Error';
				$result['status_class'] = strtolower($result['status']);
				
				$result['details'] = '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
					esc_html__('No alternative text has been found for these images. Alt tags are essential for SEO and accessibility. Please edit your images in the media library or using your preferred page builder, and provide alternative text.', 'siteseo') . '</p>';
				
	
				if(!empty($image_matches[1])){
					$result['details'] .= '<ul class="attachments">';
					foreach($image_matches[1] as $index => $img){
						if(empty($alt_matches[1][$index])){
							$result['details'] .= '<li class="attachment"><figure>' .
								'<img src="' . esc_url($img) . '"/>' .
								'<figcaption style="word-break: break-all;">' . esc_html($img) . '</figcaption>' .
								'</figure></li>';
						}
					}
					$result['details'] .= '</ul>';
				}
				
				$result['details'] .= '<p>'. __('Please note that we scan all your source code, which means some missing alternative text for images may be found in your header, sidebar, or footer.', 'siteseo') .'</p>';
			} else{
    
				$result['details'] = '<p><span class="dashicons dashicons-thumbs-up"></span>' . 
					__('All alternative tags have been completed. Great job!', 'siteseo') .'</p>';
			}

			return $result;
    	}
	

	static function analyze_outbound_links($content){

		preg_match_all('/<a[^>]+href=([\'"])(?!#)([^\'"]+)[\'"][^>]*>/i', $content, $links);

		$outbound_links = array_filter($links[2], function($link){
			return strpos($link, get_site_url()) === false;
		});
		
		$total_outbound = count($outbound_links);
		$nofollow_count = preg_match_all('/rel=[\'"]nofollow[\'"]/', implode(' ', $links[0]));
		
		$status = $total_outbound > 0 ? 'Good' : 'Warning';
		
		$details = '';
		
		$details .= '<p>'. __('The internet is based on the concept of hyperlinks, so linking to different websites is completely natural. However, avoid linking to low-quality or spammy sites. If youre uncertain about a site quality, add the "nofollow" attribute to your link.', 'siteseo') .'</p>';
		
		if($total_outbound > 0){
			/* translators: %s represents the detected outbound links on page  */
			$details .= '<p>'.sprintf(__('We detected %s outbound links on your page. Below is the list.', 'siteseo'), $total_outbound) .'</p>';
			$details .= '<ul>';
			
			foreach($outbound_links as $link){
				$details .= '<li><span class="dashicons dashicons-arrow-right"></span>';
				$details .= '<a href="'.esc_url($link).'" target="_blank">'.esc_url($link).'</a></li>';
			}
			
			$details .= '</ul>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
				__('This page does not contain any outbound links.', 'siteseo') . '</p>';
		}
		
		return [
			'label' => __('Outbound Links', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}
	
	static function analyze_internal_links($content){

		preg_match_all('/<a[^>]+href=([\'"])(?!#)([^\'"]+)[\'"][^>]*>(.*?)<\/a>/i', $content, $links, PREG_SET_ORDER);

		$internal_links = array_filter($links, function($link) {
			return strpos($link[2], get_site_url()) !== false;
		});
		
		$total_internal = count($internal_links);

		$status = $total_internal > 0 ? 'Good' : 'Warning';
		
		$details = '';

		$details .= '<p>'. __('Internal links are crucial for both SEO and user experience. Always aim to interconnect your content using meaningful and relevant anchor text.', 'siteseo') .'</p>';
		
		if($total_internal > 0){
			/* translators: %s represents the internal links pointing to page */
			$details .= '<p>'. sprintf(__('We identified %s internal links pointing to this page.', 'siteseo'), $total_internal) .'</p>';
			$details .= '<ul>';
	
			foreach($internal_links as $link){
				$url = $link[2];
				$post_id = url_to_postid($url);
				
				$details .= '<li><span class="dashicons dashicons-arrow-right"></span>';
				$details .= '<a href="'.esc_url($url) .'" target="_blank">'. esc_html($url) . '</a>';
				
				if($post_id){
					$details .= '<a class="nounderline" href="' . get_edit_post_link($post_id) . '" ' .
							   'title="' . 
							   /* translators: %s represents the degree of severity */
							   sprintf(__('edit %s', 'siteseo'), esc_html(get_the_title($post_id))) . '">' .
							   '<span class="dashicons dashicons-edit-large"></span></a>';
				}
				
				$details .= '</li>';
			}
			
			$details .= '</ul>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
				__('This page has no internal links from other content. Links from archive pages are not counted as internal links because they lack contextual relevance.', 'siteseo') . '</p>';
		}
		
		return [
			'label' => __('Internal Links', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}
	
	static function analyze_nofollow_links($content){
	
		preg_match_all('/<a[^>]+href=([\'"])([^\'"]+)[\'"][^>]*>(.*?)<\/a>/i', $content, $all_links, PREG_SET_ORDER);
		
		$nofollow_links = array_filter($all_links, function($link){
			return preg_match('/rel=[\'"][^\'"]*nofollow[^\'"]*[\'"]/', $link[0]);
		});
		
		$total_nofollow = count($nofollow_links);

		$status = $total_nofollow > 0 ? 'Warning' : 'Good';
		
		$details = '';
		
		if($total_nofollow > 0){
			
			$details .= '<p>' .
			/* translators: %d represents the number nofollow attribute */ 
			sprintf( esc_html__('We found %d links with the nofollow attribute on your page. Avoid overusing the nofollow attribute in links. Below is the list:', 'siteseo'),
				$total_nofollow
			) . '</p>';
			
			$details .= '<ul>';
			
			foreach($nofollow_links as $link){
				$href = $link[2];
				$link_text = $link[3];
				
				$details .= '<li>'.
					'<span class="dashicons dashicons-arrow-right"></span>'.
					'<a href="' . esc_url($href) . '" target="_blank">'.esc_html($link_text).'</a>'.
					'<span class="dashicons dashicons-external"></span>'.
					'</li>';
			}
			
			$details .= '</ul>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' . 
				__('This page does not contain any nofollow links.', 'siteseo') . '</p>';
		}
		
		return [
			'label' => __('Nofollow Links', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}

	static function check_headings($content, $keywords = []) {
		$details = '';
		$status = 'Good';
		$status_class = 'good';
		if(empty(trim($content))){
			return [
				'label' => 'Headings',
				'status' => 'Warning',
				'status_class' => 'warning',
				'details' => '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('No content available to check headings.', 'siteseo') . '</p>'
			];
		}

		preg_match_all('/<h([1-6])([^>]*)>(.*?)<\/h\1>/is', $content, $heading_matches);
		
		if(empty($heading_matches[0])){
			return [
				'label' => 'Headings',
				'status' => 'Error',
				'status_class' => 'error',
				'details' => '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('No headings found in the content. Using headings is essential for both SEO and accessibility!', 'siteseo') . '</p>'
			];
		}

		$heading_counts = array_count_values($heading_matches[1]);
		$total_headings = count($heading_matches[0]);

		
		$h1_count = isset($heading_counts[1]) ? $heading_counts[1] : 0;
		if($h1_count > 0){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . 
				/* translators: %d represents the number of h1 tags */
				sprintf(esc_html__('We found %d Heading 1 (H1) tags in your content.', 'siteseo'), $h1_count+1) . '</p>';

			$details .= '<p>' . __('You should avoid using more than one H1 heading in your post content. The rule is simple: each web page should have only one H1, which benefits both SEO and accessibility. Below is the list:', 'siteseo') . '</p>';

			$details .= '<ul>';
			foreach(array_keys($heading_matches[1], '1') as $index){
				$details .= '<li><span class="dashicons dashicons-arrow-right"></span>' . 
					wp_strip_all_tags($heading_matches[0][$index]) . '</li>';
			}
			$details .= '</ul>';
			$status = 'Warning';
			$status_class = 'warning';
		}
		foreach([2, 3] as $level){
			$level_count = isset($heading_counts[$level]) ? $heading_counts[$level] : 0;
			$details .= '<p><span class="dashicons dashicons-info"></span>' .
				/* translators: %d represents the heading */ 
				sprintf(__('Found %1$d H%2$d heading(s)', 'siteseo'), $level_count, $level) . '</p>';

			if($level_count > 0){
				$details .= '<ul>';
				foreach(array_keys($heading_matches[1], (string)$level) as $index){
					$details .= '<li><span class="dashicons dashicons-arrow-right"></span>'. 
						wp_strip_all_tags($heading_matches[0][$index]) .'</li>';
				}
				$details .= '</ul>';
			}

			if(!empty($keywords) && $level_count > 0){
				$keyword_found = false;
				$keyword_details = '<ul>';
				
				foreach($keywords as $kw_name){
					$kw_count = 0;
					foreach(array_keys($heading_matches[1], (string)$level) as $index){
						$kw_count += substr_count(
							strtolower(wp_strip_all_tags($heading_matches[0][$index])), 
							strtolower($kw_name)
						);
					}
					
					if($kw_count > 0){
						$keyword_found = true;
						$keyword_details .= '<li><span class="dashicons dashicons-arrow-right"></span>' .
							/* translators: %s represents the degree of severity */ 
							sprintf(esc_html__('%1$s was found %2$d times.', 'siteseo'), $kw_name, $kw_count) . '</li>';
					}
				}
				$keyword_details .= '</ul>';

				if($keyword_found){
					$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' .
						/* translators: %s represents the target keywords  */ 
						sprintf(__('Target keywords were found in Heading %1$d (H%2$d).', 'siteseo'), $level, $level) . '</p>' . 
						$keyword_details;
				} else{
					$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' .
						/* translators: %d represents the target keywords */ 
						sprintf(__('None of your target keywords were found in Heading %1$d (H%2$d).', 'siteseo'), $level, $level) . '</p>';
					if($status === 'Good'){
						$status = 'Warning';
						$status_class = 'warning';
					}
				}
			}
		}

		return [
			'label' => 'Headings',
			'status' => $status,
			'status_class' => $status_class,
			'details' => $details
		];
	}
	
	static function check_social_meta_tags($post = null){
		if(!$post){
			$post = get_queried_object();
		}
		
		$details = '';
		$status = 'Good';
		$status_class = 'good';
		
		$og_titles = get_post_meta($post->ID, '_siteseo_social_fb_title', true);
		$og_title = $og_titles ? $og_titles : '';
		
		if(empty($og_title)){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your Open Graph Title tag has not been set!', 'siteseo') .'</p>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your Open Graph Title is missing!', 'siteseo') .'</p>';
			$status = 'Error';
			$status_class = 'error';
		} else{
			$details .= '<h4>'. __('Open Graph Title', 'siteseo') . '</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('An Open Graph Title tag was found in your source code.', 'siteseo') . '</p>';
			$details .= '<ul><li><span class="dashicons dashicons-arrow-right"></span>' . esc_html($og_title) . '</li></ul>';
		}

		$og_descriptions = get_post_meta($post->ID, '_siteseo_social_fb_desc', true);
		$og_description = $og_descriptions ? $og_descriptions : '';

		if(empty($og_description)){
			$details .= '<h4>'. __('Open Graph Description', 'siteseo') .'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your Open Graph Description has not been set!','siteseo').'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = $status_class === 'good' ? 'warning' : $status_class;
		} else {
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' .
				/* translators: %s represents the og description */
				sprintf(esc_html__('We found %s og:description in your content.', 'siteseo'), $og_descriptions) . '</p>';
		}

		// OG Check
		$og_images = get_post_meta($post->ID, '_siteseo_social_fb_img', true);
		$og_image = $og_images ? $og_images : '';
		
		if(empty($og_image)){
			$details .= '<h4>'. __('Open Graph Image', 'siteseo') .'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your Open Graph Image has not been set!' ,'siteseo') .'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = $status_class === 'good' ? 'warning' : $status_class;
		} else{
			/* translators: %s represents the og images */
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. sprintf(esc_html__('We found %s og:image in your content.', 'siteseo'), $og_images) . '</p>';
		}

		// Open Graph
		$og_site_name = get_bloginfo('name');
		if(empty($og_site_name)){
			$details .= '<h4>'. __('Open Graph Site Name', 'siteseo') .'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your Open Graph Site Name has not been set!' ,'siteseo') .'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = ($status_class === 'good') ? 'warning' : $status_class;
		}

		// Twitter
		$twitter_title = get_post_meta($post->ID, '_siteseo_social_twitter_title', true);
		if(empty($twitter_title)){
			$details .= '<h4>'. __('X Title', 'siteseo').'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your X Title has not been set!', 'siteseo').'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = $status_class === 'good' ? 'warning' : $status_class;
		}

		$twitter_description = get_post_meta($post->ID, '_siteseo_social_twitter_desc', true);
		if(empty($twitter_description)){
			$details .= '<h4>'. __('X Description','siteseo').'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your X Description has not been set!','siteseo') .'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = $status_class === 'good' ? 'warning' : $status_class;
		}

		$twitter_image = get_post_meta($post->ID, '_siteseo_social_twitter_img', true);
		if(empty($twitter_image)){
			$details .= '<h4>'. __('X Image', 'siteseo') .'</h4>';
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('Your X Image has not been set!', 'siteseo').'</p>';
			$status = $status === 'Good' ? 'Warning' : $status;
			$status_class = ($status_class === 'good') ? 'warning' : $status_class;
		}

		return [
			'label' => __('Social Meta Tags', 'siteseo'),
			'status' => $status,
			'status_class' => $status_class,
			'details' => $details
		];

	}

    static function check_structured_data($post){
        $schema_type = get_post_meta($post->ID, '_siteseo_structured_data_type', true);
        $status = !empty($schema_type) ? 'Good' : 'Warning';

        return [
            'label' => 'Structured Data',
            'status' => $status,
            'status_class' => strtolower($status),
            'details' => !empty($schema_type) ? 'Schema Type: '.$schema_type : 'No schema defined'
        ];
    }

	static function check_keywords_in_permalink($permalink, $keywords){
		$keywords = array_filter(explode(',', trim($keywords)));
		$permalink = str_replace('-', ' ', strtolower(basename($permalink)));
		$content_words = str_word_count($permalink, 1);
		$count_words = count($content_words);


		$kw_density = [];
		$matching_keywords = [];
		
		foreach($keywords as $keyword){
			$keyword_occurrence = 0;
			$keyword = strtolower(trim($keyword));
			
			// If keyword has multiple words
			if(str_word_count($keyword) > 1){
				$pattern = '/\b' . preg_quote($keyword, '/') . '\b/i';
				preg_match_all($pattern, $permalink, $matches);
				$keyword_occurrence = count($matches[0]);
			} else {
				$word_counts = array_count_values($content_words);
				$keyword_occurrence = isset($word_counts[$keyword]) ? $word_counts[$keyword] : 0;
			}
		
			// Calculate density as percentage
			$kw_density[] = ($keyword_occurrence * str_word_count($keyword) * 100)/$count_words;
			if(count($kw_density) > 0){
				$matching_keywords[] = $keyword;
				break;
			}
		}

		$status = !empty($kw_density) ? 'Good' : 'Error';

		$details = '';
		if($status === 'Good'){	
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('Great! One of your target keywords is included in your permalink.', 'siteseo') .'</p>';
			$details .= '<ul><li><span class="dashicons dashicons-arrow-right"></span>' . implode(', ', $matching_keywords) . '</li></ul>';
		} elseif($permalink === get_home_url() || $permalink === home_url()){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('This is your homepage, so this check doesn\'t apply as there is no slug.', 'siteseo') . '</p>';
		} else{
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('You should include one of your target keywords in your permalink.', 'siteseo') . '</p>';
		}

		return [
			'label' => __('Keywords in Permalink', 'siteseo'),
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
		
	}
	
	static function check_meta_robots($post){

		$noindex = get_post_meta($post->ID, '_siteseo_robots_index', true);
		$nofollow = get_post_meta($post->ID, '_siteseo_robots_follow', true);
		$noimageindex = get_post_meta($post->ID, '_siteseo_robots_imageindex', true);
		$noarchive = get_post_meta($post->ID, '_siteseo_robots_archive', true);
		$nosnippet = get_post_meta($post->ID, '_siteseo_robots_snippet', true);

		$count_meta_robots = 0;
		$details = '';

		$meta_robots_checks = [
			'noindex' => $noindex,
			'nofollow' => $nofollow,
			'noimageindex' => $noimageindex,
			'noarchive' => $noarchive,
			'nosnippet' => $nosnippet,
		];

		foreach($meta_robots_checks as $robot => $value){
			if($value !== 'yes'){
				continue;
			}

			$count_meta_robots++;
			switch($robot){
				case 'noindex':
					$details .= '<p data-robots="noindex"><span class="dashicons dashicons-thumbs-down"></span>' . __('<strong>noindex</strong> is enabled! Search engines cannot index this page', 'siteseo') . '</p>';
					break;
				case 'nofollow':
					$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('<strong>nofollow</strong> is on! Search engines can\'t follow your links on this page.', 'siteseo') . '</p>';
					break;
				case 'noimageindex':
					$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('<strong>nofollow</strong> is enabled! Search engines cannot follow the links on this page.', 'siteseo').'</p>';
					break;
				case 'noarchive':
					$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('<strong>noarchive</strong> is enabled! Search engines will not cache your page.', 'siteseo') .'</p>';
					break;
				case 'nosnippet':
					$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>' . __('<strong>nosnippet</strong> is enabled! Search engines will not display a snippet of this page in the search results.', 'siteseo') .'</p>';
					break;
			}
		}

		if($count_meta_robots > 0){
			/* translators: %s represents the robots tags */ 
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. sprintf(esc_html__('We found %s meta robots tags on your page. There may be an issue with your theme!', 'siteseo'), $count_meta_robots) .'</p>';
		}
		
		if($noindex !== 'yes'){
			$details .= '<p data-robots="index"><span class="dashicons dashicons-thumbs-up"></span>'. __('<strong>noindex</strong> is disabled. Search engines will index this page.', 'siteseo') .'</p>';
		}
		if($nofollow !== 'yes'){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('<strong>nofollow</strong> is disabled. Search engines will follow links on this page.', 'siteseo') .'</p>';
		}
		
		if($noimageindex !== 'yes'){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('<strong>noimageindex</strong> is disabled. Google will index the images on this page.', 'siteseo') .'</p>';
		}
		if($noarchive !== 'yes'){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('<strong>noarchive</strong> is disabled. Search engines will probably cache your page.', 'siteseo') .'</p>';
		}
		if($nosnippet !== 'yes'){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>'. __('<strong>nosnippet</strong> is disabled. Search engines will display a snippet of this page in search results.', 'siteseo') .'</p>';
		}
		
		if($count_meta_robots === 0){
			$details .= '<p><span class="dashicons dashicons-thumbs-up"></span>' . __('We found no meta robots on this page. It means, your page is index,follow. Search engines will index it, and follow links. ', 'siteseo') . '</p>';
		}

		$status = ($count_meta_robots === 0) ? 'Good' : 
				  (($count_meta_robots <= 2) ? 'Warning' : 'Error');

		return [
			'label' => 'Meta Robots',
			'status' => $status,
			'status_class' => strtolower($status),
			'details' => $details
		];
	}

    static function check_last_modified_date($post){
        $last_modified = get_the_modified_date('Y-m-d', $post);
        $days_since_modified = round((time() - strtotime($last_modified)) / (60 * 60 * 24));

        $status = $days_since_modified < 30 ? 'Good' : 
                  ($days_since_modified < 90 ? 'Warning' : 'Error');
				  
		$details = '';
		
		if($status == 'Error'){
			$details .= '<p><span class="dashicons dashicons-thumbs-down"></span>'. __('This post is a little old!', 'siteseo') .'</p>';
		}
		
		if($days_since_modified < 365){
			$details .='<p><span class="dashicons dashicons-thumbs-up"></span>'.__('The last modified date of this article is less than 1 year. Cool', 'siteseo') .'</p>';
		}
		
		$details .= '<p>'.__('Search engines love fresh content. Update regularly your articles without entirely rewriting your content and give them a boost in search rankings. SiteSEO takes care of the technical part', 'siteseo').'</p>';

        return [
            'label' => 'Last Modified Date',
            'status' => $status,
            'status_class' => strtolower($status),
			'details' => $details
        ];
    }
	
	static function analyze_readability($post, $title){
		$data = [];

		// These are power words specifically for headlines.
		// These are not hard rules, but they are perceived to have a higher CTR if used in the heading.
		$power_words = ['exclusive', 'revealed', 'secrets', 'ultimate', 'proven', 'unleashed', 'discover', 'breakthrough', 'shocking', 'insider', 'elite', 'uncovered', 'powerful', 'guaranteed', 'transformative', 'instant', 'revolutionary', 'unbelievable', 'top', 'best', 'must-have', 'limited', 'rare', 'unique', 'unprecedented', 'premium', 'urgent', 'today', 'now', 'latest', 'new', 'free', 'bonus', 'offer', 'sensational', 'astonishing', 'incredible', 'jaw-dropping', 'unmissable', 'essential', 'critical', 'vital', 'pivotal', 'game-changer', 'spotlight', 'trending', 'hot', 'popular', 'featured', 'special', 'limited-time', 'hurry', 'last chance', 'countdown'];
		
		if(!empty($title)){
			// Checking power words.
			$title_words = explode(' ', strtolower($title));

			$present_power_words = array_intersect($title_words, $power_words);

			if(!empty($present_power_words)){
				$data['power_words'] = $present_power_words;
			}

			// Checking number in the Title
			if(preg_match('/\s?\d+\s/', preg_quote($title), $number)){
				$data['number_found'] = $number[0];
			}
		}
		
		// We are checking paragarph length too.
		if(!isset($data['paragraph_length'])){
			$data['paragraph_length'] = 0;
		}
		
		if(!empty($post)){
			preg_match_all('/<p>.*<\/p>/U', $post, $paragraphs);

			foreach($paragraphs[0] as $paragraph){
				$paragraph = normalize_whitespace(wp_strip_all_tags($paragraph));
				
				$data['paragraph_length'] += substr_count($paragraph, ' ') + 1; // updating paragraph length
				self::analyse_passive_voice($paragraph, $data);
			}
		}

		return $data;
	}
	
	static function analyse_passive_voice($paragraph, &$data){

		if(empty($paragraph)){
			return;
		}

		$sentences = explode('.', $paragraph);
		$passive_count = 0;

		if(!isset($data['passive_voice']['passive_sentences'])){
			$data['passive_voice']['passive_sentences'] = 0;
		}
		
		if(!isset($data['passive_voice']['total_sentences'])){
			$data['passive_voice']['total_sentences'] = 0;
		}

		if(count($sentences) === 0){
			return;
		}

		foreach($sentences as $sentence){
			if(empty($sentence)){
				continue;
			}

			$sentence = normalize_whitespace($sentence);
			$is_passive = self::sentence_is_passive($sentence);
			
			if($is_passive == true){
				$passive_count++;
			}
		}

		$data['passive_voice']['passive_sentences'] += $passive_count;
		$data['passive_voice']['total_sentences'] += count($sentences);
	}

	static function sentence_is_passive($sentence){
		$be_words = ['am', 'is', 'are', 'was', 'were', 'be', 'being', 'been'];

		// TODO: We can check if "en" ending words are a comman pattern too, then we will remove the en ending words too from here.
		$past_particles = ['gone' ,'done' ,'seen' ,'taken' ,'eaten' ,'written' ,'driven' ,'spoken' ,'broken' ,'chosen' ,'fallen' ,'forgotten' ,'forgiven' ,'hidden' ,'known' ,'grown' ,'drawn' ,'flown' ,'thrown' ,'blown' ,'shown' ,'worn' ,'sworn' ,'torn' ,'woken' ,'begun' ,'sung' ,'run' ,'swum' ,'shaken' ,'given' ,'proven' ,'ridden' ,'risen' ,'shone' ,'shot' ,'fought' ,'thought' ,'bought' ,'brought' ,'caught' ,'taught' ,'built' ,'felt' ,'kept' ,'slept' ,'left' ,'lost' ,'meant' ,'met' ,'read' ,'sold' ,'sent' ,'spent' ,'stood' ,'understood' ,'won' ,'held' ,'told' ,'heard' ,'paid' ,'laid' ,'said' ,'found' ,'made' ,'learned' ,'put'];
		
		if(empty($sentence)){
			return false;
		}
		
		$words = explode(' ', $sentence);

		for($i = 0; $i < count($words); $i++){
			// Checking if we have a be word
			if(!in_array($words[$i], $be_words)){
				continue;
			}

			// If be word is there then need to check if next one is past particle with mostly ends with ed.
			if(strpos($words[$i+1], 'ed') != strlen($words[$i+1]) - 2){
				if(!in_array($words[$i+1], $past_particles)){
					continue;
				}
			}

			return true;
		}

		return false;
	}

	static function get_bricks_page_content($bricks_page){

		if(empty($bricks_page) || !is_array($bricks_page)){
			return;
		}

		$content = \Bricks\Frontend::render_data($bricks_page);

		$content = strip_shortcodes($content); // remove shortcodes
		$content = wp_strip_all_tags($content); // remove HTML tags

		return $content;
	}

}
metaboxes/settings.php000064400000215572151526415240011125 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO\Metaboxes;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Settings{

	static function render_metabox(){
		global $siteseo;

		$metabox_data = [];
		
		$show_content_analysis = true;
		
		if(is_user_logged_in()){
			
			if(is_super_admin()){
				
				$siteseo->display_ca_metaboxe = 1;
				$show_content_analysis = true;
			} else{
				$user = wp_get_current_user();
				$siteseo_user_role = current($user->roles);
				$siteseo_options = get_option('siteseo_advanced_option_name');
				
				$ca_metabox_roles = !empty($siteseo_options['security_metaboxe_ca_role']) ? $siteseo_options['security_metaboxe_ca_role'] : [];
				
				if(array_key_exists($siteseo_user_role, $ca_metabox_roles)){
					$siteseo->display_ca_metaboxe = 1;
					$show_content_analysis = false;
				}
			}
		}
		
		$metabox_data = self::metabox_data();
		self::metabox_form_html($metabox_data, $show_content_analysis);
	}
	
	static function metabox_data(){
		global $post, $siteseo;

		$metabox_data = [];
		$metabox_data['title'] = $post->post_title;
		$metabox_data['excerpt'] = $post->post_excerpt;

		// Getting the first paragraph of the post
		if(empty($metabox_data['excerpt'])){
			$post_seperated = get_extended($post->post_content);

			if(!empty($post_seperated['main'])){
				$metabox_data['excerpt'] = wp_strip_all_tags($post_seperated['main']);
			}
		}

		$metabox_data['keywords'] = get_post_meta($post->ID, 'siteseo_analysis_target_kw',true);
		$metabox_data['meta_title'] = get_post_meta($post->ID, '_siteseo_titles_title', true);
		$metabox_data['meta_desc'] = get_post_meta($post->ID, '_siteseo_titles_desc', true);
		$metabox_data['robots_canonical'] = get_post_meta($post->ID, '_siteseo_robots_canonical', true);
		$metabox_data['robots_primary_cat'] = get_post_meta($post->ID, '_siteseo_robots_primary_cat', true);
		$metabox_data['fb_title'] = get_post_meta($post->ID, '_siteseo_social_fb_title', true);
		$metabox_data['fb_desc'] = get_post_meta($post->ID, '_siteseo_social_fb_desc', true);
		$metabox_data['fb_img'] = get_post_meta($post->ID, '_siteseo_social_fb_img', true);
		$siteseo_social_fb_img_attachment_id = get_post_meta($post->ID, '_siteseo_social_fb_img_attachment_id', true);
		$siteseo_social_fb_img_width = get_post_meta($post->ID, '_siteseo_social_fb_img_width', true);
		$siteseo_social_fb_img_height = get_post_meta($post->ID, '_siteseo_social_fb_img_height', true);
		$metabox_data['x_title'] = get_post_meta($post->ID, '_siteseo_social_twitter_title', true);
		$metabox_data['x_desc'] = get_post_meta($post->ID, '_siteseo_social_twitter_desc', true);
		$metabox_data['x_img'] = get_post_meta($post->ID, '_siteseo_social_twitter_img', true);
		$siteseo_social_twitter_img_attachment_id = get_post_meta($post->ID, '_siteseo_social_twitter_img_attachment_id', true);
		$siteseo_social_twitter_img_width	= get_post_meta($post->ID, '_siteseo_social_twitter_img_width', true);
		$siteseo_social_twitter_img_height	= get_post_meta($post->ID, '_siteseo_social_twitter_img_height', true);
		$metabox_data['redirections_enabled'] = get_post_meta($post->ID, '_siteseo_redirections_enabled', true);
		$metabox_data['redirections_enabled_regex']	= get_post_meta($post->ID, '_siteseo_redirections_enabled_regex', true);
		$metabox_data['redirections_logged_status']	= get_post_meta($post->ID, '_siteseo_redirections_logged_status', true);
		$metabox_data['redirections_type'] = get_post_meta($post->ID, '_siteseo_redirections_type', true);
		$metabox_data['redirections_value'] = get_post_meta($post->ID, '_siteseo_redirections_value', true);
		$metabox_data['redirections_param'] = get_post_meta($post->ID, '_siteseo_redirections_param', true);

		$title_options = get_option('siteseo_titles_option_name', []);
		$metabox_data['disabled_robots'] = [
			'robots_index' => '',
			'robots_follow' => '',
			'archive' => '',
			'snippet' => '',
			'imageindex' => '',
		];

		if(post_password_required($post->ID) === true || !empty($title_options['titles_noindex'])){
			$metabox_data['robots_index'] = 'yes';
			$metabox_data['disabled_robots']['robots_index'] = 'disabled';
		} else{
			$metabox_data['robots_index'] = get_post_meta($post->ID, '_siteseo_robots_index', true);
		}
		
		if(!empty($title_options['titles_nofollow'])){
			$metabox_data['robots_follow'] = 'yes';
			$metabox_data['disabled_robots']['robots_follow'] = 'disabled';
		} else{
			$metabox_data['robots_follow'] = get_post_meta($post->ID, '_siteseo_robots_follow', true);
		}
		
		if(!empty($title_options['titles_noarchive'])){
			$metabox_data['robots_archive'] = 'yes';
			$metabox_data['disabled_robots']['archive'] = 'disabled';
		} else{
			$metabox_data['robots_archive'] = get_post_meta($post->ID, '_siteseo_robots_archive', true);
		}

		if(!empty($title_options['titles_nosnippet'])){
			$metabox_data['robots_snippet'] = 'yes';
			$metabox_data['disabled_robots']['snippet'] = 'disabled';
		} else{
			$metabox_data['robots_snippet'] = get_post_meta($post->ID, '_siteseo_robots_snippet', true);
		}

		if(!empty($title_options['titles_noimageindex'])){
			$metabox_data['robots_imageindex'] = 'yes';
			$metabox_data['disabled_robots']['imageindex'] = 'disabled';
		} else{
			$metabox_data['robots_imageindex'] = get_post_meta($post->ID, '_siteseo_robots_imageindex', true);
		}

		return $metabox_data;
	}
	
	static function metabox_term_data($term){
		global $tag;

		$metabox_data = [];

		$metabox_data['title'] = $tag->name;
		$metabox_data['excerpt'] = $tag->description;
		$metabox_data['meta_title'] = get_term_meta($term->term_id, '_siteseo_titles_title', true);
		$metabox_data['meta_desc'] = get_term_meta($term->term_id, '_siteseo_titles_desc', true);

		// Social Fields
		$metabox_data['fb_title'] = get_term_meta($term->term_id, '_siteseo_social_fb_title', true);
		$metabox_data['fb_desc'] = get_term_meta($term->term_id, '_siteseo_social_fb_desc', true);
		$metabox_data['fb_img'] = get_term_meta($term->term_id, '_siteseo_social_fb_img', true);
		$metabox_data['x_title'] = get_term_meta($term->term_id, '_siteseo_social_twitter_title', true);
		$metabox_data['x_desc'] = get_term_meta($term->term_id, '_siteseo_social_twitter_desc', true);
		$metabox_data['x_img'] = get_term_meta($term->term_id, '_siteseo_social_twitter_img', true);
		
		// Social Dimensions
		$fb_img_id = get_term_meta($term->term_id, '_siteseo_social_fb_img_attachment_id', true);
		$fb_img_width = get_term_meta($term->term_id, '_siteseo_social_fb_img_width', true);
		$fb_img_height = get_term_meta($term->term_id, '_siteseo_social_fb_img_height', true);
		$x_img_id = get_term_meta($term->term_id, '_siteseo_social_twitter_img_attachment_id', true);
		$x_img_width = get_term_meta($term->term_id, '_siteseo_social_twitter_img_width', true);
		$x_img_height = get_term_meta($term->term_id, '_siteseo_social_twitter_img_height', true);

		// Redirection fields
		$metabox_data['redirections_enabled'] = get_term_meta($term->term_id, '_siteseo_redirections_enabled', true);
		$metabox_data['redirections_logged_status']	= get_term_meta($term->term_id, '_siteseo_redirections_logged_status', true);
		$metabox_data['redirections_type'] = get_term_meta($term->term_id, '_siteseo_redirections_type', true);
		$metabox_data['redirections_value'] = get_term_meta($term->term_id, '_siteseo_redirections_value', true);
		$metabox_data['robots_canonical']= get_term_meta($term->term_id, '_siteseo_robots_canonical', true);

		$title_options = get_option('siteseo_titles_option_name', []);
		$metabox_data['disabled_robots'] = [
			'robots_index' => '',
			'robots_follow' => '',
			'archive' => '',
			'snippet' => '',
			'imageindex' => '',
		];

		if(!empty($title_options['titles_noindex'])){
			$metabox_data['robots_index'] = 'yes';
			$metabox_data['disabled_robots']['robots_index'] = 'disabled';
		} else {
			$metabox_data['robots_index'] = get_term_meta($term->term_id, '_siteseo_robots_index', true);
		}

		if(!empty($title_options['titles_nofollow'])){
			$metabox_data['robots_follow'] = 'yes';
			$metabox_data['disabled_robots']['robots_follow'] = 'disabled';
		} else {
			$metabox_data['robots_follow'] = get_term_meta($term->term_id, '_siteseo_robots_follow', true);
		}

		if(!empty($title_options['titles_noarchive'])){
			$metabox_data['robots_archive'] = 'yes';
			$metabox_data['disabled_robots']['archive'] = 'disabled';
		} else {
			$metabox_data['robots_archive'] = get_term_meta($term->term_id, '_siteseo_robots_archive', true);
		}

		if(!empty($title_options['titles_nosnippet'])){
			$metabox_data['robots_snippet'] = 'yes';
			$metabox_data['disabled_robots']['snippet'] = 'disabled';
		} else {
			$metabox_data['robots_snippet'] = get_term_meta($term->term_id, '_siteseo_robots_snippet', true);
		}

		if(!empty($title_options['titles_noimageindex'])){
			$metabox_data['robots_imageindex'] = 'yes';
			$metabox_data['disabled_robots']['imageindex'] = 'disabled';
		} else {
			$metabox_data['robots_imageindex'] = get_term_meta($term->term_id, '_siteseo_robots_imageindex', true);
		}

		return $metabox_data;
	}
		
	static function metabox_form_html(&$metabox_data, $show_content_analysis = false){
		global $siteseo, $post, $pagenow, $typenow;
		
		$pro_settings = isset($siteseo->pro) ? $siteseo->pro : '';
		
		// Checked x is enabled global settings
		$enable_x_card = !empty($siteseo->social_settings['social_twitter_card']);
		
		$data_attr = [];
		$data_attr['data_tax'] = '';
		$data_attr['termId'] = '';

		if('post-new.php' == $pagenow || 'post.php' == $pagenow){
			$data_attr['current_id'] = $post->ID;
			$data_attr['origin'] = 'post';
			$data_attr['title'] = get_the_title($data_attr['current_id']);
		} elseif('term.php' == $pagenow || 'edit-tags.php' == $pagenow){
			global $tag;
			$data_attr['current_id'] = $tag->term_id;
			$data_attr['termId'] = $tag->term_id;
			$data_attr['origin'] = 'term';
			$data_attr['data_tax'] = $tag->taxonomy;
			$data_attr['title'] = $tag->name;
		}

		$data_attr['isHomeId'] = get_option('page_on_front');
		if($data_attr['isHomeId'] === '0'){
			$data_attr['isHomeId'] = '';
		}

		// Static Data
		$home_url = home_url();
		$parsed_url = wp_parse_url($home_url);
		$host_uri = $parsed_url['host'];
		$social_placeholder = SITESEO_ASSETS_URL . '/img/social-placeholder.png';

		$metabox_tag_drop_kses = [
			'button' => [
				'class' => true,
				'type' => true,
			],
			'span' => [
				'class' => true,
			],
			'div' => [
				'class' => true,
				'style' => true,
			],
			'input' => [
				'type' => true,
				'class' => true,
				'name' => true,
				'spellcheck' => true,
				'placeholder' => true,
			],
			'ul' => true,
			'li' => [
				'class' => true,
				'data-*' => true,
				'tabindex' => true,
			]
		];
		
		// Preview of social title and description
		$current_screen = get_current_screen();

		if(!empty($current_screen) && $current_screen->base === 'term'){
			$term_id = isset($_GET['tag_ID']) ? (int)$_GET['tag_ID'] : 0;
			$taxonomy = $current_screen->taxonomy;
		} else{
			$post_type = $current_screen->post_type;
		}

		$site_title_placeholder = '';
		$site_desc_placeholder = '';
		$social_preview_title = '';
		$social_preview_desc = '';
		
		if(!empty($post_type) && !empty($siteseo->titles_settings['titles_single_titles'][$post_type]['title'])){
			$site_title_placeholder = $siteseo->titles_settings['titles_single_titles'][$post_type]['title'];
		} elseif(!empty($taxonomy) && !empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy]['title'])){
			$site_title_placeholder = $siteseo->titles_settings['titles_tax_titles'][$taxonomy]['title'];
		} else{
			$site_title_placeholder = $metabox_data['title'];
		}
		
		if(!empty($post_type) && !empty($siteseo->titles_settings['titles_single_titles'][$post_type]['description'])){
			$site_desc_placeholder = $siteseo->titles_settings['titles_single_titles'][$post_type]['description'];
		} elseif(!empty($taxonomy) && !empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy]['description'])){
			$site_desc_placeholder =  $siteseo->titles_settings['titles_tax_titles'][$taxonomy]['description'];
		} else{
			$site_desc_placeholder = $metabox_data['excerpt'];
		}

		if(!empty($metabox_data['meta_title'])){
			$social_preview_title = $metabox_data['meta_title'];
		} elseif(!empty($post_type) && !empty($siteseo->titles_settings['titles_single_titles'][$post_type]['title'])){
			$social_preview_title = $siteseo->titles_settings['titles_single_titles'][$post_type]['title'];
		} elseif(!empty($taxonomy) && !empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy]['title'])){
			$social_preview_title = $siteseo->titles_settings['titles_tax_titles'][$taxonomy]['title'];
		} else{
			$social_preview_title = get_the_title();
		}
		
		
		if(!empty($metabox_data['meta_desc'])){
			$social_preview_desc = $metabox_data['meta_desc'];
		} elseif(!empty($post_type) && !empty($siteseo->titles_settings['titles_single_titles'][$post_type]['description'])){
			$social_preview_desc = $siteseo->titles_settings['titles_single_titles'][$post_type]['description'];
		} elseif(!empty($taxonomy) && !empty($siteseo->titles_settings['titles_tax_titles'][$taxonomy]['description'])){
			$social_preview_desc = $siteseo->titles_settings['titles_tax_titles'][$taxonomy]['description'];
		} else{
			$social_preview_desc = get_bloginfo('description');
		}
		
		if(empty($siteseo->advanced_settings['appearance_ca_metaboxe']) && !empty($show_content_analysis)){
			$siteseo_metabox_tabs = [
				'content-analysis' => __('Content Analysis', 'siteseo')
			];
		}

		$siteseo_metabox_tabs['title-settings'] = __('Title', 'siteseo');
		$siteseo_metabox_tabs['social-settings'] = __('Social', 'siteseo');
		$siteseo_metabox_tabs['advanced-settings'] = __('Advanced', 'siteseo');

		$siteseo_metabox_tabs['redirect'] = __('Redirects', 'siteseo');
		
		if(!empty($pro_settings['enable_structured_data']) && !empty($pro_settings['toggle_state_stru_data']) && !empty($show_content_analysis)){
			$siteseo_metabox_tabs['structured-data-types'] = __('Structured Data Types', 'siteseo');
		}
		
		if(!empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap']) && !empty($show_content_analysis)){
			$siteseo_metabox_tabs['video-sitemap'] = __('Video Sitemap', 'siteseo');
		}
		
		if(!empty($pro_settings['toggle_state_google_news']) && !empty($pro_settings['google_news']) && !empty($show_content_analysis)){
			$siteseo_metabox_tabs['google-news'] = __('Google News', 'siteseo');
		}

		echo'<div id="siteseo-metabox-wrapper" class="siteseo-metabox-wrapper">
		<div class="siteseo-metabox-tabs" data-home-id="'.esc_attr($data_attr['isHomeId']).'" data-term-id="'.esc_attr($data_attr['termId']).'" data_id="'.esc_attr($data_attr['current_id']).'" data_origin="'.esc_attr($data_attr['origin']).'" data_tax="'.esc_attr($data_attr['data_tax']).'">';
		
		wp_nonce_field('siteseo_metabox_nonce', 'siteseo_metabox_nonce');

		foreach($siteseo_metabox_tabs as $siteseo_metabox_tab => $siteseo_metabox_tab_title){
			$selected_metabox_tab = '';

			if($siteseo_metabox_tab === 'content-analysis'){
				$selected_metabox_tab = 'siteseo-metabox-tab-label-active';
			}

			if(empty($siteseo->display_ca_metaboxe) && $siteseo_metabox_tab === 'title-settings'){
				$selected_metabox_tab = 'siteseo-metabox-tab-label-active';
			}			
			
			echo'<div class="siteseo-metabox-tab-label '.esc_attr($selected_metabox_tab).'" data-tab="siteseo-metabox-tab-'.esc_attr($siteseo_metabox_tab).'">';
			
			if($siteseo_metabox_tab === 'advanced-settings' && !empty($metabox_data['robots_index'])){
				echo'<span class="dashicons dashicons-hidden siteseo-noindex-warning"></span>';
			}
			
			echo esc_html($siteseo_metabox_tab_title).'</div>';
		}
			
		$home_url = home_url();
		$parsed_home_url = wp_parse_url($home_url);
		
		$ai_logo = SITESEO_ASSETS_URL . '/img/siteseo-ai.svg';
		
		$meta_desc_percentage = '1';
		if(!empty($metabox_data['meta_desc'])){
			$meta_desc_percentage = (strlen($metabox_data['meta_desc'])/160)*100;
		} elseif(!empty($metabox_data['excerpt'])){
			$meta_desc_percentage = (strlen($metabox_data['excerpt'])/160)*100;
		}

		if(intval($meta_desc_percentage) > 100){
			$meta_desc_percentage = '100';
		}

		$meta_title_percentage = '1';
		if(!empty($metabox_data['meta_title'])){
			$meta_title_percentage = (strlen($metabox_data['meta_title'])/60)*100;
		} else if(!empty($metabox_data['title'])){
			$meta_title_percentage = (strlen($metabox_data['title'])/60)*100;
		}

		if(intval($meta_title_percentage) > 100){
			$meta_title_percentage = '100';
		}

		echo'</div>';
		if(empty($siteseo->advanced_settings['appearance_ca_metaboxe']) && $show_content_analysis){
			echo'<div class="siteseo-sidebar-tabs siteseo-sidebar-tabs-opened"><span>'.esc_html__('Content Analysis', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
			<div class="siteseo-metabox-tab-content-analysis siteseo-metabox-tab" style="display:block;">';
				self::content_analysis($post);
			echo'</div>';
		}
		
		$allowed_suggestion_tags = array(
			'button' => array(
				'class' => array(),
				'type' => array(),
			),
			'span' => array(
				'id' => array(),
				'class' => array(),
			),
			'div' => array(
				'class' => array(),
				'style' => array(),
			),
			'input' => array(
				'type' => array(),
				'class' => true,
				'placeholder' => true,
			)
		);
		
		// if all x-settings empty then use same as og option enabled
		$use_og_settings = (empty($metabox_data['x_title']) && empty($metabox_data['x_desc']) && empty($metabox_data['x_img']));
		
		// show image in preview
		if(!empty($metabox_data['x_img'])){
			$x_image = $metabox_data['x_img'];
		} else if(!empty($metabox_data['fb_img']) && !empty($use_og_settings)){ // use og enabled
			$x_image = $metabox_data['fb_img'];
		} else{
			$x_image = $social_placeholder;
		}
		
		// x preview title
		if(!empty($metabox_data['x_title'])){
			$x_title_preview = $metabox_data['x_title'];
		} else if($metabox_data['fb_title'] &&  !empty($use_og_settings)){
			$x_title_preview = $metabox_data['fb_title'];
		} else {
			$x_title_preview = $social_preview_title;
		}
		
		echo'<div class="siteseo-sidebar-tabs '.(empty($siteseo->display_ca_metaboxe) ? 'siteseo-sidebar-tabs-opened' : '').'"><span>'.esc_html__('Title', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
		<div class="siteseo-metabox-tab-title-settings siteseo-metabox-tab" style="'.(empty($siteseo->display_ca_metaboxe) ? 'display:block;' : '').'">
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label>'.esc_html__('Search Preview','siteseo').'</label>
			</div>
			<div class="siteseo-metabox-search-preview">
				<div class="siteseo-search-preview-toggle">
					<span id="siteseo-metabox-search-pc" style="display:none">'.esc_html__('Show Desktop version', 'siteseo').'</span>
					<span id="siteseo-metabox-search-mobile">'.esc_html__('Show Mobile version', 'siteseo').'</span>
				</div>
				<div class="siteseo-search-preview-desktop">
					<div class="siteseo-search-preview-metadata">
						<div style="background-color: #e2eeff; border: 1px solid #e2eeff; height:28px; width:28px; padding: 3px; border-radius: 50px; display:flex; align-items:center; justify-content:center;">
						<svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#0060f0"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"></path></svg>
						</div>
						<div class="siteseo-search-preview-metadata-link">
							<div>'.esc_url($parsed_home_url['host']).'</div>
							<div><cite>'.esc_url(home_url()).'</cite></div>
						</div>
						<div>
						<svg focusable="false" xmlns="http://www.w3.org/2000/svg" width="20" viewBox="0 0 24 24"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg>
						</div>
					</div>
					<h3>'.(!empty($metabox_data['meta_title']) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($metabox_data['meta_title'], true)) : (!empty($site_title_placeholder) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($site_title_placeholder, true)) : 'Post Title here')).'</h3>
					<div class="siteseo-search-preview-description">
					'.(!empty($metabox_data['meta_desc']) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($metabox_data['meta_desc'], true)) : (!empty($site_desc_placeholder) ? esc_html(substr(\SiteSEO\TitlesMetas::replace_variables($site_desc_placeholder, true), 0, 160)) : 'Post description')).'
					</div>
					
				</div>
			</div>
		</div>
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_titles_title_meta">'.esc_html__('Title', 'siteseo').'</label>
			</div>
			<div class="siteseo-metabox-input-wrap">
				<div class="siteseo-metabox-tags">
					<button type="button" class="siteseo-metabox-tag" data-tag="%%post_title%%"><span class="dashicons dashicons-plus"></span> Post Title</button>
					<button type="button" class="siteseo-metabox-tag" data-tag="%%sitetitle%%"><span class="dashicons dashicons-plus"></span> Site Title</button>
					<button type="button" class="siteseo-metabox-tag" data-tag="%%sep%%"><span class="dashicons dashicons-plus"></span>Seperator</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
					if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
						echo'<span class="siteseo-ai-modal-open" data-context="site-page" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
					}
				echo'</div>
				<input type="text" id="siteseo_titles_title_meta" class="siteseo_titles_title_meta" name="siteseo_titles_title" placeholder="'.(!empty($site_title_placeholder) ? esc_attr(\SiteSEO\TitlesMetas::replace_variables($site_title_placeholder, true)) : esc_html__('Enter title for this post', 'siteseo')).'" value="'.(!empty($metabox_data['meta_title']) ? esc_html($metabox_data['meta_title']) : '').'"/>
				<div class="siteseo-metabox-limits">
					<span class="siteseo-metabox-limits-meter"><span style="width:'.esc_attr($meta_title_percentage).'%"></span></span>
					<span class="siteseo-metabox-limits-numbers"><em>'.esc_html(strlen($metabox_data['meta_title'])).'</em> out of 60 max recommended characters</span>
				</div>
			</div>
		</div>
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_titles_desc_meta">'.esc_html__('Meta Description', 'siteseo').'</label>
			</div>
			<div class="siteseo-metabox-input-wrap">
				<div class="siteseo-metabox-tags">
					<button type="button" class="siteseo-metabox-tag" data-tag="%%post_excerpt%%"><span class="dashicons dashicons-plus"></span> Post Excerpt</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
					if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
						echo'<span class="siteseo-ai-modal-open" data-context="site-page" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
					}
				echo'</div>
				<textarea id="siteseo_titles_desc_meta" class="siteseo_titles_desc_meta" name="siteseo_titles_desc" rows="2" placeholder="'.(!empty($site_desc_placeholder) ? esc_attr(substr(\SiteSEO\TitlesMetas::replace_variables($site_desc_placeholder, true), 0, 160)) : esc_html__('Enter description for this post', 'siteseo')).'">'.(!empty($metabox_data['meta_desc']) ? esc_html($metabox_data['meta_desc']) : '').'</textarea>
				<div class="siteseo-metabox-limits">
					<span class="siteseo-metabox-limits-meter"><span style="width:'.esc_attr($meta_desc_percentage).'%"></span></span>
					<span class="siteseo-metabox-limits-numbers"><em>'.esc_html(strlen($metabox_data['meta_desc'])).'</em> out of 160 max recommended characters</span>
				</div>
			</div>
		</div>
		</div>

		<div class="siteseo-sidebar-tabs"><span>'.esc_html__('Social', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
		<div class="siteseo-metabox-tab-social-settings siteseo-metabox-tab">
			<div class="siteseo-metabox-subtabs">
				<div class="siteseo-metabox-tab-label siteseo-metabox-tab-label-active" data-tab="siteseo-metabox-tab-fb-settings">Facebook</div>
				<div class="siteseo-metabox-tab-label" data-tab="siteseo-metabox-tab-x-settings">X(Twitter)</div>
			</div>
			<div class="siteseo-metabox-tab-fb-settings siteseo-metabox-tab" style="display:block;">
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label>'.esc_html__('Preview', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-fb-preview">
					<div class="siteseo-metabox-fb-image">
						<img src="'.(!empty($metabox_data['fb_img']) ? esc_url($metabox_data['fb_img']) : esc_url($social_placeholder)).'" alt="Facebook preview"/>
					</div>
					<div class="siteseo-metabox-fb-data">
						<div class="siteseo-metabox-fb-host">'.(!empty($host_uri) ? esc_html($host_uri) : '').'</div>
						<div class="siteseo-metabox-fb-title">'.(!empty($metabox_data['fb_title']) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($metabox_data['fb_title'], true)) : esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_title, true))).'</div>
						<div class="siteseo-metabox-fb-desc">'.(!empty($metabox_data['fb_desc']) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($metabox_data['fb_desc'], true)) : esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_desc, true))).'</div>
					</div>
				</div>
			</div>
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_fb_title_meta">'.esc_html__('Facebook Title', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<input type="text" id="siteseo_social_fb_title_meta" class="siteseo_social_fb_title_meta" name="siteseo_social_fb_title" placeholder="'.(!empty($social_preview_title) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_title, true)) : '').'" value="'.(!empty($metabox_data['fb_title']) ? esc_attr($metabox_data['fb_title']) : '').'" />
					<div class="siteseo-metabox-tags">
						<button type="button" class="siteseo-facebook-title" data-tag="%%post_title%%"><span class="dashicons dashicons-plus"></span> Post Title</button>
						<button type="button" class="siteseo-facebook-title" data-tag="%%sitetitle%%"><span class="dashicons dashicons-plus"></span> Site Title</button>
						<button type="button" class="siteseo-facebook-title" data-tag="%%sep%%"><span class="dashicons dashicons-plus"></span>Seperator</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
						if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
							echo'<span class="siteseo-ai-modal-open" data-context="og" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
						}
					echo'</div>
				</div>
			</div>

			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_fb_desc_meta">'.esc_html__('Facebook description', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<textarea id="siteseo_social_fb_desc_meta" class="siteseo_social_fb_desc_meta" name="siteseo_social_fb_desc" rows="2" placeholder="'.(!empty($social_preview_desc) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_desc, true)) : '').'">'.(!empty($metabox_data['fb_desc']) ? esc_html($metabox_data['fb_desc']) : '').'</textarea>
					<div class="siteseo-metabox-tags">
						<button type="button" class="siteseo-facebook-desc" data-tag="%%post_excerpt%%"><span class="dashicons dashicons-plus"></span> Post Excerpt</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
						if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
							echo'<span class="siteseo-ai-modal-open" data-context="og" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
						}
					echo'</div>
				</div>
			</div>

			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_fb_img_meta">'.esc_html__('Facebook Thumbnail', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<span style="color:red; font-weight:bold; display:none;"></span>
					<input type="text" id="siteseo_social_fb_img_meta" name="siteseo_social_fb_img" class="siteseo_social_fb_img_meta" placeholder="'.esc_html__('Enter URL of the Image you want to be shown as the Facebook image', 'siteseo').'" value="'.(!empty($metabox_data['fb_img']) ? esc_url($metabox_data['fb_img']) : '').'"/>
					<p class="description">'.esc_html__('Minimum size: 200x200px, ideal ratio 1.91:1, 8Mb max. (eg: 1640x856px or 3280x1712px for retina screens).', 'siteseo').'</p>
					<input type="hidden" name="siteseo_social_fb_img_attachment_id" id="siteseo_social_fb_img_attachment_id" class="siteseo_social_fb_img_attachment_id" value="">
					<input type="hidden" name="siteseo_social_fb_img_width" id="siteseo_social_fb_img_width" class="siteseo_social_fb_img_width" value="">
					<input type="hidden" name="siteseo_social_fb_img_height" id="siteseo_social_fb_img_height" class="siteseo_social_fb_img_height" value="">
					<button class="components-button is-secondary" id="siteseo_social_fb_img_upload">Upload Image</button>
				</div>
			</div>
			</div>

			<div class="siteseo-metabox-tab-x-settings siteseo-metabox-tab">
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label>'.esc_html__('Preview','siteseo').'</label>
				</div>
				<div>
				<div class="siteseo-metabox-x-preview">
					<div class="siteseo-metabox-x-image">
						<img src="'.($x_image ? esc_url($x_image) : '').'" alt="X preview"/>
					</div>
					<div class="siteseo-metabox-x-data">
						<div class="siteseo-metabox-x-title">'.(!empty($x_title_preview) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($x_title_preview, true)) : '').'</div>
					</div>
				</div>
				<div class="siteseo-metabox-x-host">From '.(!empty($host_uri) ? esc_html($host_uri) : '').'</div>
				</div>
			</div>';
			
			if(!empty($enable_x_card)){
				
				echo'<div class="siteseo-metabox-option-wrap">
					<div class="siteseo-metabox-label-wrap">
						<label>'.esc_html__('Use same as Facebook settings', 'siteseo').'</label>
					</div>
					<div class="siteseo-metabox-input-wrap">
						<label class="siteseo-x-toggle-switch">';
							$checked = !empty($metabox_data['x_title'] || $metabox_data['x_desc'] || $metabox_data['x_img']) ? '' : "checked=checked";
							
							echo'<input name="siteseo_social_use_og_settings" type="checkbox" '.esc_html($checked).'/>
							<span class="siteseo-x-slider"></span>
						</label>
					</div>
				</div>';
			}
			
			if(!empty($enable_x_card)){
				echo'<div class="siteseo-x-settings" '.(!empty($use_og_settings) ? 'style="display:none;"' : '').'>';
			}
			
			echo'<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_twitter_title_meta">'.esc_html__('X Title', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<input type="text" id="siteseo_social_twitter_title_meta" class="siteseo_social_twitter_title_meta" name="siteseo_social_twitter_title" placeholder="'.(!empty($social_preview_title) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_title, true)) : '').'" value="'.(!empty($metabox_data['x_title']) ? esc_attr($metabox_data['x_title']) : '').'" />
					<div class="siteseo-metabox-tags">
						<button type="button" class="siteseo-x-title" data-tag="%%post_title%%"><span class="dashicons dashicons-plus"></span> Post Title</button>
						<button type="button" class="siteseo-x-title" data-tag="%%sitetitle%%"><span class="dashicons dashicons-plus"></span> Site Title</button>
						<button type="button" class="siteseo-x-title" data-tag="%%sep%%"><span class="dashicons dashicons-plus"></span>Seperator</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
						if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
							echo'<span class="siteseo-ai-modal-open" data-context="twitter" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
						}
					echo'</div>
				</div>
			</div>
			
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_twitter_desc_meta">'.esc_html__('X description', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<textarea id="siteseo_social_twitter_desc_meta" class="siteseo_social_twitter_desc_meta" name="siteseo_social_twitter_desc" rows="2" placeholder="'.(!empty($social_preview_desc) ? esc_html(\SiteSEO\TitlesMetas::replace_variables($social_preview_desc, true)) : '').'">'.(!empty($metabox_data['x_desc']) ? esc_attr($metabox_data['x_desc']) : '').'</textarea>
					<div class="siteseo-metabox-tags">
						<button type="button" class="siteseo-x-desc" data-tag="%%post_excerpt%%"><span class="dashicons dashicons-plus"></span> Post Excerpt</button>'.wp_kses(siteseo_suggestion_button_metabox(), $allowed_suggestion_tags);
						if(defined('SITESEO_PRO_VERSION') && !defined('SITEPAD')){
							echo'<span class="siteseo-ai-modal-open" data-context="twitter" title="SiteSEO AI Assistant"><img src="'.esc_url($ai_logo).'" alt="AI Assistant Icon">'.'<label class="siteseo-ai-modal-label">'.esc_html__('Ask AI', 'siteseo').'</label></span>';
						}
					echo'</div>
				</div>
			</div>
			
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_social_twitter_img_meta">'.esc_html__('X Thumbnail', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<span style="color:red; font-weight:bold; display:none;"></span>
					<input type="text" id="siteseo_social_twitter_img_meta" class="siteseo_social_twitter_img_meta" name="siteseo_social_twitter_img" placeholder="'.esc_html__('Enter URL of the Image you want to be shown as the X image', 'siteseo').'" value="'.(!empty($metabox_data['x_img']) ? esc_attr($metabox_data['x_img']) : '').'" />
					<p class="description">'.esc_html__('Minimum size: 144x144px (300x157px with large card enabled), ideal ratio 1:1 (2:1 with large card), 5Mb max.', 'siteseo').'</p>
					<input type="hidden" name="siteseo_social_twitter_img_attachment_id" id="siteseo_social_twitter_img_attachment_id" class="siteseo_social_twitter_img_attachment_id" value="">
					<input type="hidden" name="siteseo_social_twitter_img_width" id="siteseo_social_twitter_img_width" class="siteseo_social_twitter_img_width" value="">
					<input type="hidden" name="siteseo_social_twitter_img_height" id="siteseo_social_twitter_img_height" class="siteseo_social_twitter_img_height" value="">
					<button class="components-button is-secondary" id="siteseo_social_twitter_img_upload">Upload Image</button>
				</div>
			</div>';

			if(!empty($enable_x_card)){
				echo'</div>';
			}
			
			echo'</div>
		</div>';
		
		if(!empty($pro_settings['enable_structured_data']) && !empty($pro_settings['toggle_state_stru_data']) && !empty($show_content_analysis)){
			echo'<div class="siteseo-sidebar-tabs"><span>'.esc_html__('Structured Data Types', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
			<div class="siteseo-metabox-tab-structured-data-types siteseo-metabox-tab">';
				// Pro fearure
				do_action('siteseo_display_structured_data_types');
			echo'</div>';
		}
		
		// video sitemap
		if(!empty($pro_settings['toggle_state_video_sitemap']) && !empty($pro_settings['enable_video_sitemap']) && !empty($show_content_analysis)){
			echo'<div class="siteseo-sidebar-tabs"><span>'.esc_html__('Video Sitemap', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
			<div class="siteseo-metabox-tab-video-sitemap siteseo-metabox-tab">';
				do_action('siteseo_display_video_sitemap');
			echo'</div>';
		}
		
		// gooogle news exclude 
		if(!empty($pro_settings['toggle_state_google_news']) && !empty($pro_settings['google_news']) && !empty($show_content_analysis)){
			echo'<div class="siteseo-sidebar-tabs"><span>'.esc_html__('Google News', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
			<div class="siteseo-metabox-tab-google-news siteseo-metabox-tab">';
				do_action('siteseo_display_google_news');
			echo'</div>';
		}
		
		echo'<div class="siteseo-sidebar-tabs"><span>';

		if(!empty($metabox_data['robots_index'])){
			echo'<span class="dashicons dashicons-hidden siteseo-noindex-warning"></span>';
		}
		
		echo esc_html__('Advanced', 'siteseo').'</span><span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span></span></div>
		
		<div class="siteseo-metabox-tab-advanced-settings siteseo-metabox-tab">
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_social_twitter_img_meta">'.esc_html__('Meta Robots Settings', 'siteseo').'</label>
				<p class="description">'.
				/* translators: %s represents the degree of severity */
				wp_kses_post(sprintf(__('You cannot uncheck a checkbox? This is normal, and it\'s most likely defined in the <a href="%s">global settings of the plugin.</a>', 'siteseo'), esc_url(admin_url('admin.php?page=siteseo-titles#tab=tab_siteseo_titles_single')))).'</p>
			</div>
			<div class="siteseo-metabox-input-wrap">';
				
			$robots_options = [
				'siteseo_robots_index_meta' => [
					'desc' => __('Do not display this page in search engine results / Sitemaps', 'siteseo'),
					'short' => 'noindex',
					'name' => 'siteseo_robots_index',
					'checked' => $metabox_data['robots_index'],
					'disabled' => $metabox_data['disabled_robots']['robots_index']
				],
				'siteseo_robots_follow_meta' => [
					'desc' => __('Do not follow links for this page', 'siteseo'),
					'short' => 'nofollow',
					'name' => 'siteseo_robots_follow',
					'checked' => $metabox_data['robots_follow'],
					'disabled' => $metabox_data['disabled_robots']['robots_follow']
				],
				'siteseo_robots_imageindex_meta' => [
					'desc' => __('Do not index images for this page', 'siteseo'),
					'short' => 'noimageindex',
					'name' => 'siteseo_robots_imageindex',
					'checked' => $metabox_data['robots_imageindex'],
					'disabled' => $metabox_data['disabled_robots']['imageindex']
				],
				'siteseo_robots_archive_meta' => [
					'desc' => __('Do not display a "Cached" link in the Google search results', 'siteseo'),
					'short' => 'noarchive',
					'name' => 'siteseo_robots_archive',
					'checked' => $metabox_data['robots_archive'],
					'disabled' => $metabox_data['disabled_robots']['archive']
				],
				'siteseo_robots_snippet_meta' => [
					'desc' => __('Do not display a description in search results for this page', 'siteseo'),
					'short' => 'nosnippet',
					'name' => 'siteseo_robots_snippet',
					'checked' => $metabox_data['robots_snippet'],
					'disabled' => $metabox_data['disabled_robots']['snippet']
				]
			];

			foreach($robots_options as $robots_id => $robots_option){
				$checked = '';
				if(!empty($robots_option['checked'])){
					$checked = 'checked';
				}
				
				$disabled = '';
				if(!empty($robots_option['disabled'])){
					$disabled = 'disabled';
					$robots_option['name'] = '';
				}

				echo'<label for="'.esc_attr($robots_id).'" style="display:block; margin-bottom:5px;">
					<input type="checkbox" value="yes" id="'.esc_attr($robots_id).'" class="siteseo-metabox-robots-options" name="'.esc_attr($robots_option['name']).'" '.esc_attr($checked).' '.esc_attr($disabled).'/>
					'.esc_html($robots_option['desc']).' ('.esc_html($robots_option['short']).')
				</label>';
			}
			
			echo'</div>
		</div>
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_robots_canonical_meta">'.esc_html__('Canonical URL', 'siteseo').'</label>
			</div>
			<div class="siteseo-metabox-input-wrap">
				<input id="siteseo_robots_canonical_meta" type="text" name="siteseo_robots_canonical" placeholder="'.esc_url(get_the_permalink()).'" value="'.(!empty($metabox_data['robots_canonical']) ? esc_html($metabox_data['robots_canonical']) : '').'">
			</div>
		</div>';

		if(!empty($pagenow) && !empty($typenow) && ($pagenow == 'post.php' || $pagenow == 'post-new.php') && ($typenow == 'post' || $typenow == 'product')){

			$categories = (object)[];
			if($typenow == 'product'){
				$categories = get_the_terms($post, 'product_cat');
			} else{
				$categories = get_categories();
			}
			
			if(!empty($categories) && !is_wp_error($categories)){
				echo'<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_robots_canonical_meta">'.esc_html__('Select a primary category', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<select id="siteseo_robots_primary_cat" name="siteseo_robots_primary_cat">';
						foreach($categories as $category){
							$selected = '';
							if(!empty($metabox_data['robots_primary_cat']) && $metabox_data['robots_primary_cat'] == $category->term_id){
								$selected = 'selected';
							}

							echo'<option value="'.esc_attr($category->term_id).'" '.esc_attr($selected).'>'.esc_html($category->name).'</option>'; 
						}
					echo'</select>
				</div>
			</div>';
			}
		}
		echo'</div>

		<div class="siteseo-sidebar-tabs"><span>'.esc_html__('Redirects', 'siteseo').'</span>
			<span class="siteseo-sidebar-tabs-arrow"><span class="dashicons dashicons-arrow-down-alt2"></span>
		</span></div>
		
		<div class="siteseo-metabox-tab-redirect siteseo-metabox-tab">
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_redirections_enabled_meta">'.esc_html__('Enable redirection', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<input id="siteseo_redirections_enabled_meta" type="checkbox" name="siteseo_redirections_enabled" value="1" '.(!empty($metabox_data['redirections_enabled']) ? 'checked' : '').'>
				</div>
			</div>
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_redirections_enabled_meta">'.esc_html__('Login status', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<select name="siteseo_redirections_logged_status" id="siteseo_redirections_logged_status">
						<option value="both" '.(!empty($metabox_data['redirections_logged_status']) && $metabox_data['redirections_logged_status'] == 'both' ? 'selected' : '').'>'.esc_html__('All', 'siteseo').'</option>
						<option value="only_logged_in" '.(!empty($metabox_data['redirections_logged_status']) && $metabox_data['redirections_logged_status'] == 'only_logged_in' ? 'selected' : '').'>'.esc_html__('Only when logged In', 'siteseo').'</option>
						<option value="only_not_logged_in" '.(!empty($metabox_data['redirections_logged_status']) && $metabox_data['redirections_logged_status'] == 'only_not_logged_in' ? 'selected' : '').'>'.esc_html__('Only when not logged in', 'siteseo').'</option>
					</select>
				</div>
			</div>
			<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_redirections_type">'.esc_html__('Redirection Type', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<select name="siteseo_redirections_type" id="siteseo_redirections_type">
						<option value="301" '.(!empty($metabox_data['redirections_type']) && $metabox_data['redirections_type'] == '301' ? 'selected' : '').'>'.esc_html__('301 Moved Permanently', 'siteseo').'</option>
						<option value="302" '.(!empty($metabox_data['redirections_type']) && $metabox_data['redirections_type'] == '302' ? 'selected' : '').'>'.esc_html__('302 Found / Moved Temporarily', 'siteseo').'</option>
						<option value="307" '.(!empty($metabox_data['redirections_type']) && $metabox_data['redirections_type'] == '307' ? 'selected' : '').'>'.esc_html__('307 Moved Temporarily', 'siteseo').'</option>';
						if($typenow === 'siteseo_404'){
							echo'<option value="410" '.(!empty($metabox_data['redirections_type']) && $metabox_data['redirections_type'] == '410' ? 'selected' : '').'>'.esc_html__('410 Gone', 'siteseo').'</option>
							<option value="451" '.(!empty($metabox_data['redirections_type']) && $metabox_data['redirections_type'] == '451' ? 'selected' : '').'>'. esc_html__('451 Unavailable For Legal Reasons', 'siteseo').'</option>';
						}
					echo'</select>
				</div>
		</div>
		<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_redirections_value_meta">'.esc_html__('Redirection URL', 'siteseo').'</label>
			</div>
			<div class="siteseo-metabox-input-wrap">
				<input id="siteseo_redirections_value_meta" type="text" name="siteseo_redirections_value" value="'.(!empty($metabox_data['redirections_value']) ? esc_attr($metabox_data['redirections_value']): '').'">
			</div>
			<input type="hidden" id="analysis_tabs" name="analysis_tabs" value="'.esc_html(wp_json_encode(array_keys($siteseo_metabox_tabs))).'">
		</div>';
		// Note
		if($typenow === 'siteseo_404'){
			echo'<div class="siteseo-metabox-option-wrap">
				<div class="siteseo-metabox-label-wrap">
					<label for="siteseo_redirections_param">'.esc_html__('Query parameters', 'siteseo').'</label>
				</div>
				<div class="siteseo-metabox-input-wrap">
					<select name="siteseo_redirections_param" id="siteseo_redirections_param">
						<option value="exact_match" '.(!empty($metabox_data['redirections_param']) && $metabox_data['redirections_param'] == 'exact_match' ? 'selected' : '').'>'.esc_html__('Exactly parameters with exact match', 'siteseo').'</option>
						<option value="without_param" '.(!empty($metabox_data['redirections_param']) && $metabox_data['redirections_param'] == 'without_param' ? 'selected' : '').'>'.esc_html__('Exclude all parameters', 'siteseo').'</option>
						<option value="with_ignored_param" '.(!empty($metabox_data['redirections_param']) && $metabox_data['redirections_param'] == 'with_ignored_param' ? 'selected' : '').'>'.esc_html__('Exclude all parameters and pass them to the redirection', 'siteseo').'</option>
					</select>
				</div>
			</div>';
		}

		echo'</div>
		</div>';

	}

	static function content_analysis($post){
		
		wp_nonce_field('siteseo_ca_nonce', 'siteseo_content_analysis_nonce');

		$siteseo_real_preview = [
			'siteseo_nonce' => wp_create_nonce('siteseo_real_preview_nonce'),
			'siteseo_real_preview' => admin_url('admin-ajax.php'),
			'i18n' => ['progress' => __('Analysis in progress...', 'siteseo')],
			'ajax_url' => admin_url('admin-ajax.php'),
			'get_preview_meta_title' => wp_create_nonce('get_preview_meta_title'),
			'realtime_nonce' => wp_create_nonce('siteseo_realtime_nonce'),
		];

		$metabox_data = [];

		$metabox_data['analysis_target_kw'] = get_post_meta($post->ID, '_siteseo_analysis_target_kw', true);
		$metabox_data['analysis_data'] = get_post_meta($post->ID, '_siteseo_analysis_data', true);
		$metabox_data['readibility_data'] = get_post_meta($post->ID, '_siteseo_readibility_data', true);
		$metabox_data['meta_title'] = get_post_meta($post->ID, '_siteseo_titles_title', true);
		$metabox_data['meta_desc'] = get_post_meta($post->ID, '_siteseo_titles_desc', true);
		
		$title_options = get_option('siteseo_titles_option_name', []);

		if(self::titles_single_cpt_noindex_option() || !empty($title_options['titles_noindex']) || true === post_password_required($post->ID)){
			$metabox_data['robots_index'] = 'yes';
		} else {
			$metabox_data['robots_index'] = get_post_meta($post->ID, '_siteseo_robots_index', true);
		}

		if(post_password_required($post->ID) === true || !empty($title_options['titles_noindex']) || self::titles_single_cpt_noindex_option()){
			$metabox_data['robots_index'] = 'yes';
		} else{
			$metabox_data['robots_index'] = get_post_meta($post->ID, '_siteseo_robots_index', true);
		}

		if(!empty($title_options['titles_nofollow']) || self::titles_single_cpt_nofollow_option()){
			$metabox_data['robots_follow'] = 'yes';
		} else{
			$metabox_data['robots_follow'] = get_post_meta($post->ID, '_siteseo_robots_follow', true);
		}

		if(!empty($title_options['titles_noarchive'])){
			$metabox_data['robots_archive'] = 'yes';
		} else{
			$metabox_data['robots_archive'] = get_post_meta($post->ID, '_siteseo_robots_archive', true);
		}

		if(!empty($title_options['titles_nosnippet'])){
			$metabox_data['robots_snippet'] = 'yes';
		} else{
			$metabox_data['robots_snippet'] = get_post_meta($post->ID, '_siteseo_robots_snippet', true);
		}

		if(!empty($title_options['titles_noimageindex'])){
			$metabox_data['robots_imageindex'] = 'yes';
		} else{
			$metabox_data['robots_imageindex'] = get_post_meta($post->ID, '_siteseo_robots_imageindex', true);
		}

		$metabox_data['post_id'] = $post->ID;
		$metabox_data['readibility_data'] = get_post_meta($post->ID, '_siteseo_readibility_data', true);
		
		self::siteseo_content_analysis_tab($metabox_data);
	}
	
	
	static function titles_single_cpt_nofollow_option(){
		$siteseo_get_current_cpt = get_post_type();

		$options = get_option('siteseo_titles_option_name');
		if(!empty($options) && isset($options['titles_single_titles'][$siteseo_get_current_cpt]['nofollow'])){
			return $options['titles_single_titles'][$siteseo_get_current_cpt]['nofollow'];
		}
	}
	
	static function btn_secondary_classes() {
		//Classic Editor compatibility
		global $pagenow;
		
		$current_screen = null;
		
		if(function_exists('get_current_screen')){
			$current_screen = get_current_screen();
		}
		
		if(!empty($current_screen) && method_exists($current_screen, 'is_block_editor') && true === $current_screen->is_block_editor()){
			$btn_classes_secondary = 'components-button is-secondary';
		} elseif(isset($pagenow) && ($pagenow === 'term.php' || $pagenow === 'post.php' || $pagenow === 'post-new.php')){
			$btn_classes_secondary = 'button button-secondary';
		} else{
			$btn_classes_secondary = 'btn btnSecondary';
		}

		return $btn_classes_secondary;
	}
	
	static function siteseo_content_analysis_tab(&$metabox_data){
		global $post;
		
		echo '<div class="siteseo-metabox-option-wrap">
			<div class="siteseo-metabox-label-wrap">
				<label for="siteseo_titles_title_meta">' . esc_html__('Focus Keywords', 'siteseo') . '</label>
			</div>
			<div class="siteseo-metabox-input-wrap">
				<div id="siteseo_tags_wrapper" style="display: flex; flex-wrap: wrap; gap: 5px; padding: 5px; border: 1px solid #ccc; border-radius: 5px;">';
					if(!empty($metabox_data['analysis_target_kw'])){
						$tags_arr = explode(',', $metabox_data['analysis_target_kw']);
						
						if(count($tags_arr) > 0){
							foreach($tags_arr as $tag_name){
								echo '<span class="siteseo-tag">'.esc_html($tag_name).'<span class="siteseo-remove-tag">×</span></span>';
							}
						}
					}

					echo '<input id="siteseo_analysis_target_kw_meta" class="siteseo_analysis_target_kw_meta" type="text" placeholder="' . esc_html__('Enter your target keywords', 'siteseo') . '" style="border: none; outline: none; flex: 1; min-width: 150px;" />
					<input type="hidden" id="siteseo_tags_hidden" name="siteseo_analysis_target_kw" value="' . (!empty($metabox_data['analysis_target_kw']) ? esc_attr($metabox_data['analysis_target_kw']) : '') . '" />
				</div>
				<p class="description">Press <kbd>Enter</kbd> key on your keyboard to add keyword</p>
				<button id="siteseo_refresh_seo_analysis" type="button" style="margin-top:10px;" class="'.esc_attr(self::btn_secondary_classes()).'" data_id="'.esc_attr(get_the_ID()).'" data_post_type="'.esc_attr(get_current_screen()->post_type).'"> '.esc_html__('Refresh analysis', 'siteseo').'</button>
				<p class="description">'.esc_html__('Refresh analysis after saving the post to improve the accuracy of the analysis', 'siteseo').'</p>
			</div>
		</div>
		<div id="siteseo-metabox-content-analysis">
			<div id="siteseo-metabox-tabs-container">
				<div class="siteseo-metabox-subtabs">
				<div class="siteseo-metabox-tab-label siteseo-metabox-tab-label-active" data-tab="siteseo-metabox-seo-analysis-tab">'. esc_html__('SEO Analysis', 'siteseo').'</div>
					<div class="siteseo-metabox-tab-label" data-tab="siteseo-metabox-readibility-analysis-tab">'.esc_html__('Content Readability', 'siteseo').'</div>
				</div>
				<div id="siteseo-metabox-tab-content">
					<div class="siteseo-metabox-seo-analysis-tab siteseo-metabox-tab" style="display:block;">';
					
					$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
					$post = get_post($post_id);
					Analysis::display_seo_analysis($post);
			echo'</div>
			<div class="siteseo-metabox-readibility-analysis-tab siteseo-metabox-tab">
				<p class="description">' . 
					esc_html__('This section works as a guide to help you write, better content for your user, this do not have a direct affect on SEO, but it will help you write better content for your users which will help user stay on your site longer, or will improve the Click Through rate.
					Which will signal search engines about the userfulness and likeleyness of your content by your user which indirectly improve SEO of the page.', 'siteseo') . 
				'</p>';
				Analysis::display_content_readibility($metabox_data);
			echo'</div>
					</div>
				</div>
			</div>';
	}

	
	static function titles_single_cpt_noindex_option(){
		$siteseo_get_current_cpt = get_post_type();

		$options = get_option('siteseo_titles_option_name');
		
		if(!empty($options) && isset($options['titles_single_titles'][$siteseo_get_current_cpt]['noindex'])){
			return $options['titles_single_titles'][$siteseo_get_current_cpt]['noindex'];
		}
	}

	static function save_ca_metabox($post_id, $post){

		if(!isset($_POST['siteseo_content_analysis_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['siteseo_content_analysis_nonce'])), 'siteseo_ca_nonce')){
			return $post_id;
		}

		// Post type object
		$post_type = get_post_type_object($post->post_type);

		//Check permission
		if(!current_user_can($post_type->cap->edit_post, $post_id) || !siteseo_user_can_metabox()){
			return $post_id;
		}

		if('attachment' !== get_post_type($post_id)){
			if(isset($_POST['siteseo_analysis_target_kw'])){
				update_post_meta($post_id, '_siteseo_analysis_target_kw', self::clean_post('siteseo_analysis_target_kw'));
			} else{
				delete_post_meta($post_id, '_siteseo_analysis_target_kw');
			}
		}
	}
	
	
	static function save_metabox($post_id, $post){
		
		global $siteseo;
		
		// Security Check
		if(!isset($_POST['siteseo_metabox_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['siteseo_metabox_nonce'])), 'siteseo_metabox_nonce')){
			return $post_id;
		}

		//Post type object
		$post_type = get_post_type_object($post->post_type);
		
		//Check permission
		if(!current_user_can($post_type->cap->edit_post, $post_id) || !siteseo_user_can_metabox()){
			return $post_id;
		}
		
		if('attachment' !== get_post_type($post_id)){
			$analysis_tabs = [];
			$analysis_tabs = json_decode(self::clean_post('analysis_tabs'), true);
			
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('content-analysis', $analysis_tabs)){
				if(!empty($_POST['siteseo_analysis_target_kw'])){
					update_post_meta($post_id, '_siteseo_analysis_target_kw', self::clean_post('siteseo_analysis_target_kw'));
				} else{
					delete_post_meta($post_id, '_siteseo_analysis_target_kw');
				}
			}
			
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('title-settings', $analysis_tabs)){
				if(!empty($_POST['siteseo_titles_title'])){
					update_post_meta($post_id, '_siteseo_titles_title', self::clean_post('siteseo_titles_title'));
				} else{
					delete_post_meta($post_id, '_siteseo_titles_title');
				}
				if(!empty($_POST['siteseo_titles_desc'])){
					update_post_meta($post_id, '_siteseo_titles_desc', self::clean_post('siteseo_titles_desc'));
				} else{
					delete_post_meta($post_id, '_siteseo_titles_desc');
				}
			}
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('advanced-settings', $analysis_tabs)){
				
				if(isset($_POST['siteseo_robots_index'])){
					update_post_meta($post_id, '_siteseo_robots_index', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_robots_index');
				}
				
				if(isset($_POST['siteseo_robots_follow'])){
					update_post_meta($post_id, '_siteseo_robots_follow', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_robots_follow');
				}
				
				if(isset($_POST['siteseo_robots_imageindex'])){
					update_post_meta($post_id, '_siteseo_robots_imageindex', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_robots_imageindex');
				}
				
				if(isset($_POST['siteseo_robots_archive'])){
					update_post_meta($post_id, '_siteseo_robots_archive', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_robots_archive');
				}
				
				if(isset($_POST['siteseo_robots_snippet'])){
					update_post_meta($post_id, '_siteseo_robots_snippet', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_robots_snippet');
				}
				
				if(!empty($_POST['siteseo_robots_canonical'])){
					update_post_meta($post_id, '_siteseo_robots_canonical', self::clean_post('siteseo_robots_canonical'));
				} else{
					delete_post_meta($post_id, '_siteseo_robots_canonical');
				}
				
				if(!empty($_POST['siteseo_robots_primary_cat'])){
					update_post_meta($post_id, '_siteseo_robots_primary_cat', self::clean_post('siteseo_robots_primary_cat'));
				} else{
					delete_post_meta($post_id, '_siteseo_robots_primary_cat');
				}
			}

			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('social-settings', $analysis_tabs)){
				//Facebook
				if(!empty($_POST['siteseo_social_fb_title'])){
					update_post_meta($post_id, '_siteseo_social_fb_title', self::clean_post('siteseo_social_fb_title'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_title');
				}
				
				if(!empty($_POST['siteseo_social_fb_desc'])){
					update_post_meta($post_id, '_siteseo_social_fb_desc', self::clean_post('siteseo_social_fb_desc'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_desc');
				}
				
				if(!empty($_POST['siteseo_social_fb_img'])){
					update_post_meta($post_id, '_siteseo_social_fb_img', self::clean_post('siteseo_social_fb_img'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_img');
				}
				
				if(!empty($_POST['siteseo_social_fb_img_attachment_id']) && !empty($_POST['siteseo_social_fb_img'])){
					update_post_meta($post_id, '_siteseo_social_fb_img_attachment_id', self::clean_post('siteseo_social_fb_img_attachment_id'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_img_attachment_id');
				}
				
				if(!empty($_POST['siteseo_social_fb_img_width']) && !empty($_POST['siteseo_social_fb_img'])){
					update_post_meta($post_id, '_siteseo_social_fb_img_width', self::clean_post('siteseo_social_fb_img_width'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_img_width');
				}
				
				if(!empty($_POST['siteseo_social_fb_img_height']) && !empty($_POST['siteseo_social_fb_img'])){
					update_post_meta($post_id, '_siteseo_social_fb_img_height', self::clean_post('siteseo_social_fb_img_height'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_fb_img_height');
				}

				//Twitter
				if(!empty($_POST['siteseo_social_twitter_title'])){
					update_post_meta($post_id, '_siteseo_social_twitter_title', self::clean_post('siteseo_social_twitter_title'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_title');
				}
				
				if(!empty($_POST['siteseo_social_twitter_desc'])){
					update_post_meta($post_id, '_siteseo_social_twitter_desc', self::clean_post('siteseo_social_twitter_desc'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_desc');
				}
				
				if(!empty($_POST['siteseo_social_twitter_img'])){
					update_post_meta($post_id, '_siteseo_social_twitter_img', self::clean_post('siteseo_social_twitter_img'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_img');
				}
				
				if(!empty($_POST['siteseo_social_twitter_img_attachment_id']) && !empty($_POST['siteseo_social_twitter_img'])){
					update_post_meta($post_id, '_siteseo_social_twitter_img_attachment_id', self::clean_post('siteseo_social_twitter_img_attachment_id'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_img_attachment_id');
				}
				
				if(!empty($_POST['siteseo_social_twitter_img_width']) && !empty($_POST['siteseo_social_twitter_img'])){
					update_post_meta($post_id, '_siteseo_social_twitter_img_width', self::clean_post('siteseo_social_twitter_img_width'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_img_width');
				}
				
				if(!empty($_POST['siteseo_social_twitter_img_height']) && !empty($_POST['siteseo_social_twitter_img'])){
					update_post_meta($post_id, '_siteseo_social_twitter_img_height', self::clean_post('siteseo_social_twitter_img_height'));
				} else{
					delete_post_meta($post_id, '_siteseo_social_twitter_img_height');
				}
			}

			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('redirect', $analysis_tabs)){
				if(isset($_POST['siteseo_redirections_type'])){
					update_post_meta($post_id, '_siteseo_redirections_type', self::clean_post('siteseo_redirections_type'));
				}
				
				if(!empty($_POST['siteseo_redirections_value'])){
					update_post_meta($post_id, '_siteseo_redirections_value', self::clean_post('siteseo_redirections_value'));
				} else{
					delete_post_meta($post_id, '_siteseo_redirections_value');
				}
				
				if(isset($_POST['siteseo_redirections_param'])){
					update_post_meta($post_id, '_siteseo_redirections_param', self::clean_post('siteseo_redirections_param'));
				}
				
				if(isset($_POST['siteseo_redirections_enabled'])){
					update_post_meta($post_id, '_siteseo_redirections_enabled', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_redirections_enabled', '');
				}
				
				if(isset($_POST['siteseo_redirections_enabled_regex'])){
					update_post_meta($post_id, '_siteseo_redirections_enabled_regex', 'yes');
				} else{
					delete_post_meta($post_id, '_siteseo_redirections_enabled_regex');
				}
				
				if(isset($_POST['siteseo_redirections_logged_status'])){
					update_post_meta($post_id, '_siteseo_redirections_logged_status', self::clean_post('siteseo_redirections_logged_status'));
				} else{
					delete_post_meta($post_id, '_siteseo_redirections_logged_status');
				}
			}
			
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('structured-data-types', $analysis_tabs)){
				if(class_exists('\SiteSEOPro\StructuredData') && method_exists('\SiteSEOPro\StructuredData', 'save_metabox')){
					\SiteSEOPro\StructuredData::save_metabox($post_id, $post);
				}
			}
			
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('video-sitemap', $analysis_tabs)){
				if(class_exists('\SiteSEOPro\VideoSitemap') && method_exists('\SiteSEOPro\VideoSitemap', 'save_video_sitemap')){
					\SiteSEOPro\VideoSitemap::save_video_sitemap($post_id, $post);
				}
			}
			
			if(!empty($analysis_tabs) && is_array($analysis_tabs) && in_array('google-news', $analysis_tabs)){
				if(class_exists('\SiteSEOPro\GoogleNews') && method_exists('\SiteSEOPro\GoogleNews', 'save_google_news')){
					\SiteSEOPro\GoogleNews::save_google_news($post_id, $post);
				}
			}
		}
	}

	static function clean_post($name){
		return self::clean_post_req($name);
	}
	
	static function clean_get($name){
		return self::clean_post_req($name);
	}
	
	static function clean_post_req($name){
		if(empty($name)){
			return '';
		}
	
		if(!isset($_REQUEST[$name])){
			return '';
		}
	
		if(is_array($_REQUEST[$name]) || is_object($_REQUEST[$name])){
			return map_deep(wp_unslash($_REQUEST[$name]), 'sanitize_text_field');
		}

		return sanitize_text_field(wp_unslash($_REQUEST[$name]));
	}
	
	static function universal(){
		global $siteseo, $pagenow, $post;
		
		$post_id = !empty($_REQUEST['post']) ? (int) sanitize_text_field(wp_unslash($_REQUEST['post'])) : 0;
		
		if(empty($post_id)){
			return;
		}
		
		if(!current_user_can('edit_post', $post_id)){
			wp_die(esc_html__('You do not have access to edit this post', 'siteseo'));
		}
		
		$tmp_post = $post;
		$post = get_post($post_id);
		$tmp_pagenow = $pagenow;
		$pagenow = 'post.php';

		if(empty($post)){
			$post = $tmp_post;
			return;
		}
		
		set_current_screen($post->post_type);

		echo '<style>body{height: 100vh;} #wpcontent,#wpbody-content,html.wp-toolbar{padding:0;} .postbox .handle-order-higher, .postbox .handle-order-lower,#minor-publishing-actions,.site-menu-header{display:none !important;} #adminmenumain, #wpfooter, #wpadminbar, #wpwrap > :first-child,  #wpwrap > :nth-child(2) .lnav-col{display:none;} #wpcontent{margin:auto;} #wpbody-content{position:relative;} .siteseo-metabox-tab{background-color:white;} .siteseo-meta-submit-container{position:fixed;bottom: 20px;right : 20px;}  #siteseo_cpt form {position:relative;}.siteseo-btn{display: inline-flex;padding: 0.5rem 1rem;gap: 0.5rem;justify-content: center;align-items: center;border-radius: 0.375rem;font-size: 0.875rem;line-height: 1.25rem;font-weight: 500;white-space: nowrap;cursor:pointer;box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);border:none;text-decoration:none; text-align:center;}.siteseo-btn.primary{background-color:#141b38;color:white;} #wpwrap > :nth-child(2) > div:nth-child(2){max-width:100%}
		.siteseo-spinner{display:none;border-radius:50%;animation: siteseo-spinner 1s linear infinite;height: 0.9375rem;width: 0.9375rem;border: 2px solid #dddcdc80;border-left-color: #e3e3e3;} .siteseo-spinner-active{display:inline-block;} @keyframes siteseo-spinner{ 0% { transform: rotate(0deg);} 100% {transform: rotate(360deg);}} .components-button{align-items: center; -webkit-appearance: none; background: none; border: 0; border-radius: 2px; box-sizing: border-box; color:#1e1e1e; cursor: pointer;display: inline-flex; font-family: inherit; font-size: 13px; font-weight: 400; height: 36px; margin: 0; padding: 6px 12px; text-decoration: none; transition: box-shadow .1s linear;}.components-button.is-secondary {background: #0000; box-shadow: inset 0 0 0 1px #3858e9; color:#3858e9; outline: 1px solid #0000; white-space: nowrap;}.siteseo-sidebar-tabs{display:none;} .notice, .update-nag{ display: none !important;}</style>
		<div id="siteseo_cpt"><form id="siteseo-universal-post" action="post.php" method="post">
		<input type="hidden" name="post_id" value="'.esc_attr($post_id).'"/>';
		wp_nonce_field('siteseo_universal_nonce', 'security');
		self::render_metabox();
		
		echo '<div class="siteseo-meta-submit-container">
			<button type="submit" class="siteseo-btn primary">'.esc_html__('Save Changes', 'siteseo').'<span class="siteseo-spinner"></span></button>
		</div></form></div>
		<script>
		jQuery(document).ready(function(){
			jQuery("#siteseo-universal-post").on("submit", function(event){
				event.preventDefault();
				let jEle = jQuery(event.target),
				spinner = jEle.find(".siteseo-spinner"),
				formData = {};

				jQuery(this).serializeArray().forEach(field => {
					formData[field.name] = field.value;
				});

				formData["action"] = "siteseo_save_universal_metabox";
				
				spinner.addClass("siteseo-spinner-active");

				jQuery.ajax({
					method : "POST",
					url : "'.esc_url(admin_url('admin-ajax.php')).'",
					data : formData,
					success : function(res){
						//console.log(res);
					}
				}).always(function(){
					spinner.removeClass("siteseo-spinner-active");
				})
			});
		});
		</script>';

		$post = $tmp_post;
		$pagenow = $tmp_pagenow;

		global $wp_version;

		if(!empty($wp_version) && version_compare($wp_version, '6.4', '>')){
			remove_action('wp_footer', 'the_block_template_skip_link');
		}

		wp_footer();
		exit;
	}
	
	static function render_term_metabox($term, $taxonomy_name = ''){
		$metabox_data = self::metabox_term_data($term);
		self::metabox_form_html($metabox_data);
	}
	
	static function save_meta_terms($term_id, $post_id = 0){

		// Security Check
		if(!isset($_POST['siteseo_metabox_nonce']) || !wp_verify_nonce(self::clean_post('siteseo_metabox_nonce'), 'siteseo_metabox_nonce') ){
			return $term_id;
		}
		
		// Getting taxonomy
		$term = get_term($term_id);
		$taxonomy = get_taxonomy($term->taxonomy);

		// Is this user allowed to make these changes
		if(!current_user_can($taxonomy->cap->edit_terms, $term_id)) {
			return $term_id;
		}

		$analysis_tabs = [];
		$analysis_tabs = json_decode(self::clean_post('analysis_tabs'), true);
		
		if(empty($analysis_tabs) || !is_array($analysis_tabs)){
			return $term_id;
		}

		$tabs = [
			'title-settings' => [
				'siteseo_titles_title' => '_siteseo_titles_title',
				'siteseo_titles_desc' => '_siteseo_titles_desc',
			],
			'advanced-settings' => [
				'siteseo_robots_index' => '_siteseo_robots_index',
				'siteseo_robots_follow' => '_siteseo_robots_follow',
				'siteseo_robots_imageindex'=> '_siteseo_robots_imageindex',
				'siteseo_robots_archive' => '_siteseo_robots_archive',
				'siteseo_robots_snippet' => '_siteseo_robots_snippet',
				'siteseo_robots_canonical' => '_siteseo_robots_canonical',
			],
			'social-settings' => [
				'siteseo_social_fb_title' => '_siteseo_social_fb_title',
				'siteseo_social_fb_desc' => '_siteseo_social_fb_desc',
				'siteseo_social_fb_img' => '_siteseo_social_fb_img',
				'siteseo_social_fb_img_attachment_id' => '_siteseo_social_fb_img_attachment_id',
				'siteseo_social_fb_img_width' => '_siteseo_social_fb_img_width',
				'siteseo_social_fb_img_height' => '_siteseo_social_fb_img_height',
				'siteseo_social_twitter_title' => '_siteseo_social_twitter_title',
				'siteseo_social_twitter_desc' => '_siteseo_social_twitter_desc',
				'siteseo_social_twitter_img' => '_siteseo_social_twitter_img',
			],
			'redirect' => [
				'siteseo_redirections_type' => '_siteseo_redirections_type',
				'siteseo_redirections_logged_status' => '_siteseo_redirections_logged_status',
				'siteseo_redirections_value' => '_siteseo_redirections_value',
				'siteseo_redirections_enabled' => '_siteseo_redirections_enabled',
			]
		];
		
		// Save the key for all the options which are checkboxes
		$is_checkboxes = [
			'siteseo_robots_index',
			'siteseo_robots_follow',
			'siteseo_robots_imageindex',
			'siteseo_robots_archive',
			'siteseo_robots_snippet',
			'siteseo_redirections_enabled',
		];

		foreach($tabs as $tab => $fields){
			if(!in_array($tab, $analysis_tabs)){
				continue;
			}

			foreach($fields as $post_key => $meta_key){
				if(!empty($_POST[$post_key])){
					$value = in_array($post_key, $is_checkboxes) ? 'yes' : self::clean_post($post_key);
					update_term_meta($term_id, $meta_key, $value);
				} else {
					delete_term_meta($term_id, $meta_key);
				}
			}
		}

		return $term_id;
	}
}

import.php000064400000113655151526415240006607 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Import{

	static function rank_math(){
		$imported_count = 0;
		$log = [];
		
		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){
	 
			$robots = get_post_meta($post->ID, 'rank_math_robots', true);
			$robots_array = is_array($robots) ? $robots : [];

			$meta_mapping = [
				'_siteseo_titles_title' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_title', true),'rank_math'),
				'_siteseo_titles_desc' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_description', true),'rank_math'),
				'_siteseo_social_fb_title' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_facebook_title', true),'rank_math'),
				'_siteseo_social_fb_desc' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_facebook_description', true),'rank_math'),
				'_siteseo_social_fb_img' => get_post_meta($post->ID, 'rank_math_facebook_image', true),
				'_siteseo_social_twitter_title' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_twitter_title', true),'rank_math'),
				'_siteseo_social_twitter_desc' => self::replace_snippet_vars(get_post_meta($post->ID, 'rank_math_twitter_description', true),'rank_math'),
				'_siteseo_social_twitter_img' => get_post_meta($post->ID, 'rank_math_twitter_image', true),
				'_siteseo_robots_index' => in_array('noindex', $robots_array) ? '1' : '',
				'_siteseo_robots_follow' => in_array('nofollow', $robots_array) ? '1' : '',
				'_siteseo_robots_imageindex' => in_array('noimageindex', $robots_array) ? '1' : '',
				'_siteseo_robots_archive' => in_array('noarchive', $robots_array) ? '1' : '',
				'_siteseo_robots_snippet' => in_array('nosnippet', $robots_array) ? '1' : '',
				'_siteseo_robots_canonical' => get_post_meta($post->ID, 'rank_math_canonical_url', true),
				'_siteseo_analysis_target_kw' => get_post_meta($post->ID, 'rank_math_focus_keyword', true),
				'_siteseo_robots_primary_cat' => get_post_meta($post->ID, 'rank_math_primary_category', true)
			];
				
			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();
		
		foreach($taxonomies as $taxonomy){
			$terms = get_terms([
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]);
			
			foreach($terms as $term){
				$term_robots = get_term_meta($term->term_id, 'rank_math_robots', true);
				$term_robots_array = is_array($term_robots) ? $term_robots : [];

				$meta_mapping = [
					'_siteseo_titles_title' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_title', true),'rank_math'),
					'_siteseo_titles_desc' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_description', true),'rank_math'),
					'_siteseo_social_fb_title' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_facebook_title', true),'rank_math'),
					'_siteseo_social_fb_desc' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_facebook_description', true),'rank_math'),
					'_siteseo_social_fb_img' => get_term_meta($term->term_id, 'rank_math_facebook_image', true),
					'_siteseo_social_twitter_title' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_twitter_title', true),'rank_math'),
					'_siteseo_social_twitter_desc' => self::replace_snippet_vars(get_term_meta($term->term_id, 'rank_math_twitter_description', true),'rank_math'),
					'_siteseo_social_twitter_img' => get_term_meta($term->term_id, 'rank_math_twitter_image', true),
					'_siteseo_robots_index' => in_array('noindex', $term_robots_array) ? '1' : '',
					'_siteseo_robots_follow' => in_array('nofollow', $term_robots_array) ? '1' : '',
					'_siteseo_robots_imageindex' => in_array('noimageindex', $term_robots_array) ? '1' : '',
					'_siteseo_robots_archive' => in_array('noarchive', $term_robots_array) ? '1' : '',
					'_siteseo_robots_snippet' => in_array('nosnippet', $term_robots_array) ? '1' : '',
					'_siteseo_robots_canonical' => get_term_meta($term->term_id, 'rank_math_canonical_url', true),
					'_siteseo_analysis_target_kw' => get_term_meta($term->term_id, 'rank_math_focus_keyword', true)
				];
				
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term->term_id}";
			}
		}
		
		return [
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('Rank Math import completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}

	static function yoast_seo(){
		$imported_count = 0;
		$log = [];
    
		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){
			$yoast_robots = get_post_meta($post->ID, '_yoast_wpseo_meta-robots-adv', true);
			$robots_array = $yoast_robots ? explode(',', $yoast_robots) : [];
			
			$meta_mapping = [
				'_siteseo_titles_title' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_title', true),'yoast_seo'),
				'_siteseo_titles_desc' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_metadesc', true),'yoast_seo'),
				'_siteseo_social_fb_title' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_opengraph-title', true),'yoast_seo'),
				'_siteseo_social_fb_desc' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_opengraph-description', true),'yoast_seo'),
				'_siteseo_social_fb_img' => get_post_meta($post->ID, '_yoast_wpseo_opengraph-image', true),
				'_siteseo_social_twitter_title' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_twitter-title', true),'yoast_seo'),
				'_siteseo_social_twitter_desc' => self::replace_snippet_vars(get_post_meta($post->ID, '_yoast_wpseo_twitter-description', true),'yoast_seo'),
				'_siteseo_social_twitter_img' => get_post_meta($post->ID, '_yoast_wpseo_twitter-image', true),
				'_siteseo_robots_index' => get_post_meta($post->ID, '_yoast_wpseo_meta-robots-noindex', true) ? '1' : '',
				'_siteseo_robots_follow' => get_post_meta($post->ID, '_yoast_wpseo_meta-robots-nofollow', true) ? '1' : '',
				'_siteseo_robots_imageindex' => in_array('noimageindex', $robots_array) ? '1' : '',
				'_siteseo_robots_archive' => in_array('noarchive', $robots_array) ? '1' : '',
				'_siteseo_robots_snippet' => in_array('nosnippet', $robots_array) ? '1' : '',
				'_siteseo_robots_canonical' => get_post_meta($post->ID, '_yoast_wpseo_canonical', true),
				'_siteseo_analysis_target_kw' => get_post_meta($post->ID, '_yoast_wpseo_focuskw', true),
				'_siteseo_robots_primary_cat' => get_post_meta($post->ID, '_yoast_wpseo_primary_category', true)
			];
			
			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$yoastseo_term_meta = get_option('wpseo_taxonomy_meta');
		
		foreach($yoastseo_term_meta as $taxonomy){
			
			if(!is_array($taxonomy)){
				continue;
			}
			
			foreach($taxonomy as $term_id => $term){
				$meta_mapping = [
					'_siteseo_titles_title' => self::replace_snippet_vars((!empty($term['wpseo_title']) ? $term['wpseo_title'] : ''),'yoast_seo'),
					'_siteseo_titles_desc' => self::replace_snippet_vars((!empty($term['wpseo_desc']) ? $term['wpseo_desc'] : ''),'yoast_seo'),
					'_siteseo_social_fb_title' => self::replace_snippet_vars((!empty($term['wpseo_opengraph-title']) ? $term['wpseo_opengraph-title'] : ''),'yoast_seo'),
					'_siteseo_social_fb_desc' => self::replace_snippet_vars((!empty($term['wpseo_opengraph-description']) ? $term['wpseo_opengraph-description'] : ''),'yoast_seo'),
					'_siteseo_social_fb_img' => !empty($term['wpseo_opengraph-image']) ? $term['wpseo_opengraph-image'] : '',
					'_siteseo_social_twitter_title' => self::replace_snippet_vars((!empty($term['wpseo_twitter-title']) ? $term['wpseo_twitter-title'] : ''),'yoast_seo'),
					'_siteseo_social_twitter_desc' => self::replace_snippet_vars((!empty($term['wpseo_twitter-description']) ? $term['wpseo_twitter-description'] : ''),'yoast_seo'),
					'_siteseo_social_twitter_img' => !empty($term['wpseo_twitter-image']) ? $term['wpseo_twitter-image'] : '',
					'_siteseo_robots_index' => !empty($term['wpseo_noindex']) ? 'yes' : '',
					'_siteseo_robots_follow' => !empty($term['wpseo_nofollow']) ? 'yes' : '',
					'_siteseo_robots_imageindex' => !empty($term['wpseo_noimageindex']) ? 'yes' : '',
					'_siteseo_robots_archive' => !empty($term['wpseo_noarchive']) ? 'yes' : '',
					'_siteseo_robots_snippet' => !empty($term['wpseo_nosnippet']) ? 'yes' : '',
					'_siteseo_analysis_target_kw' => !empty($term['wpseo_focuskw']) ? $term['wpseo_focuskw'] : '',
					'_siteseo_robots_primary_cat' => !empty($term['wpseo_primary_category']) ? $term['wpseo_primary_category'] : '',
					'_siteseo_robots_canonical' => !empty($term['wpseo_canonical']) ? $term['wpseo_canonical'] : '',
				];
				
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term_id}";
			}
		}
		
		return [
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('Yoast SEO import completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}

	static function aio_seo(){
		$imported_count = 0;
		$log = [];
		
		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){

			$meta_mapping = [
				'_siteseo_titles_title' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_title', true)),'aio_seo'),
				'_siteseo_titles_desc' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_description', true)),'aio_seo'),
				'_siteseo_social_fb_title' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_og_title', true)),'aio_seo'),
				'_siteseo_social_fb_desc' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_og_description', true)),'aio_seo'),
				'_siteseo_social_fb_img' => get_post_meta($post->ID, '_aioseo_og_image', true),
				'_siteseo_social_twitter_title' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_twitter_title', true)),'aio_seo'),
				'_siteseo_social_twitter_desc' => self::replace_snippet_vars((get_post_meta($post->ID, '_aioseo_twitter_description', true)),'aio_seo'),
				'_siteseo_social_twitter_img' => get_post_meta($post->ID, '_aioseo_twitter_image', true),
				'_siteseo_robots_index' => get_post_meta($post->ID, '_aioseo_noindex', true) ? '1' : '',
				'_siteseo_robots_follow' => get_post_meta($post->ID, '_aioseo_nofollow', true) ? '1' : '',
				'_siteseo_robots_imageindex' => '1',
				'_siteseo_robots_archive' => '1',
				'_siteseo_robots_snippet' => '1', // Default to 1 if not specified
				'_siteseo_robots_canonical' => get_post_meta($post->ID, '_aioseo_canonical_url', true),
				'_siteseo_analysis_target_kw' => get_post_meta($post->ID, '_aioseo_keywords', true)
			];

			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();
		
		foreach($taxonomies as $taxonomy){
			$terms = get_terms([
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]);
			
			foreach($terms as $term){
				
				$meta_mapping = [
					'_siteseo_titles_title' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_title', true)),'aio_seo'),
					'_siteseo_titles_desc' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_description', true)),'aio_seo'),
					'_siteseo_social_fb_title' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_og_title', true)),'aio_seo'),
					'_siteseo_social_fb_desc' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_og_description', true)),'aio_seo'),
					'_siteseo_social_fb_img' => get_term_meta($term->term_id, '_aioseo_og_image', true),
					'_siteseo_social_twitter_title' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_twitter_title', true)),'aio_seo'),
					'_siteseo_social_twitter_desc' => self::replace_snippet_vars((get_term_meta($term->term_id, '_aioseo_twitter_description', true)),'aio_seo'),
					'_siteseo_social_twitter_img' => get_term_meta($term->term_id, '_aioseo_twitter_image', true),
					'_siteseo_robots_index' => get_term_meta($term->term_id, '_aioseo_noindex', true) ? '1' : '',
					'_siteseo_robots_follow' => get_term_meta($term->term_id, '_aioseo_nofollow', true) ? '1' : '',
					'_siteseo_robots_canonical' => get_term_meta($term->term_id, '_aioseo_canonical_url', true),
					'_siteseo_analysis_target_kw' => get_term_meta($term->term_id, '_aioseo_keywords', true)
				];
				
			
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term->term_id}";
			}
			
		}
		
		return	[
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('All In One SEO import completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}

	static function seo_framework(){
		$imported_count = 0;
		$log = [];

		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){
			$meta_mapping = [
				'_siteseo_titles_title' => get_post_meta($post->ID, '_genesis_title', true),
				'_siteseo_titles_desc' => get_post_meta($post->ID, '_genesis_description', true),
				'_siteseo_social_fb_title' => get_post_meta($post->ID, '_open_graph_title', true),
				'_siteseo_social_fb_desc' => get_post_meta($post->ID, '_open_graph_description', true),
				'_siteseo_social_fb_img' => get_post_meta($post->ID, '_social_image_url', true),
				'_siteseo_social_twitter_title' => get_post_meta($post->ID, '_twitter_title', true),
				'_siteseo_social_twitter_desc' => get_post_meta($post->ID, '_twitter_description', true),
				'_siteseo_social_twitter_img' => get_post_meta($post->ID, '_twitter_image', true),
				'_siteseo_robots_index' => get_post_meta($post->ID, '_genesis_noindex', true) ? '1' : '',
				'_siteseo_robots_follow' => get_post_meta($post->ID, '_genesis_nofollow', true) ? '1' : '',
				'_siteseo_robots_imageindex' => '1',
				'_siteseo_robots_archive' => '1',
				'_siteseo_robots_snippet' => '1',
				'_siteseo_robots_canonical' => get_post_meta($post->ID, '_genesis_canonical_uri', true),
				'_siteseo_analysis_target_kw' => get_post_meta($post->ID, '_genesis_keywords', true)
			];
			
			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();
		
		foreach($taxonomies as $taxonomy){
			$terms = get_terms([
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]);
			
			foreach($terms as $term){
				$term_data = get_term_meta($term->term_id, 'autodescription-term-settings', true);
				
				if(empty($term_data) || !is_array($term_data)){
					continue;
				}
				
				$meta_mapping = [
					'_siteseo_titles_title' => !empty($term_data['doctitle']) ? $term_data['doctitle'] : '',
					'_siteseo_titles_desc' => !empty($term_data['description']) ? $term_data['description'] : '',
					'_siteseo_social_fb_title' => !empty($term_data['og_title']) ? $term_data['og_title'] : '',
					'_siteseo_social_fb_desc' => !empty($term_data['og_description']) ? $term_data['og_description'] : '',
					'_siteseo_social_fb_img' => !empty($term_data['social_image_url']) ? $term_data['social_image_url'] : '',
					'_siteseo_social_twitter_title' => !empty($term_data['tw_title']) ? $term_data['tw_title'] : '',
					'_siteseo_social_twitter_desc' => !empty($term_data['tw_description']) ? $term_data['tw_description'] : '',
					'_siteseo_social_twitter_img' => !empty($term_data['social_image_url']) ? $term_data['social_image_url'] : '',
					'_siteseo_robots_index' => !empty($term_data['noindex']) ? true : '',
					'_siteseo_robots_follow' => !empty($term_data['nofollow'] ) ? true : '',
					'_siteseo_robots_archive' => !empty($term_data['noarchive']) ? true : '',
					'_siteseo_robots_canonical' => !empty($term_data['canonical']) ? $term_data['canonical'] : '',
					'_siteseo_analysis_target_kw' => !empty($term_data['keywords']) ? $term_data['keywords'] : '',
				];
			
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term->term_id}";
			}
		}

		return [
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('SEO Framework import completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}

	static function seo_press(){
		$imported_count = 0;
		$log = [];

		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){
			
			$robots_index = get_post_meta($post->ID, '_seopress_robots_index', true);
			$robots_follow = get_post_meta($post->ID, '_seopress_robots_follow', true);
			$robots_imageindex = get_post_meta($post->ID, '_seopress_robots_imageindex', true);
			$robots_archive = get_post_meta($post->ID, '_seopress_robots_archive', true);
			
			$meta_mapping = [
				'_siteseo_titles_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_post_meta($post->ID, '_seopress_titles_title', true)),
				'_siteseo_titles_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($post->ID, '_seopress_titles_desc', true)),
				'_siteseo_social_fb_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($post->ID, '_seopress_social_fb_title', true)),
				'_siteseo_social_fb_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($post->ID, '_seopress_social_fb_desc', true)),
				'_siteseo_social_fb_img' => get_post_meta($post->ID,'_seopress_social_fb_img',true),
				'_siteseo_social_twitter_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($post->ID, '_seopress_social_twitter_title', true)),
				'_siteseo_social_twitter_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($post->ID, '_seopress_social_twitter_desc', true)),
				'_siteseo_social_twitter_img' => get_post_meta($post->ID, '_seopress_social_twitter_img', true),
				'_siteseo_robots_index' => (!empty($robots_index) && $robots_index === 'yes') ? '1' : '0',
				'_siteseo_robots_follow' => (!empty($robots_follow) && $robots_follow === 'yes') ? '1' : '0',
				'_siteseo_robots_imageindex' => (!empty($robots_imageindex) && $robots_imageindex === 'yes') ? '1' : '0',
				'_siteseo_robots_archive' => (!empty($robots_archive) && $robots_archive === 'yes') ? '1' : '0',
				'_siteseo_robots_snippet' => get_post_meta($post->ID, '_seopress_robots_snippet', true),
				'_siteseo_robots_canonical' => get_post_meta($post->ID, '_seopress_robots_canonical', true),
				'_siteseo_analysis_target_kw' => get_post_meta($post->ID, '_seopress_analysis_target_kw', true),
				'_siteseo_redirections_enabled' => get_post_meta($post->ID, '_seopress_redirections_enabled', true) ? '1' : '0',
				'_siteseo_redirections_value' => get_post_meta($post->ID, '_seopress_redirections_value', true),
				'_siteseo_redirections_type' => get_post_meta($post->ID, '_seopress_redirections_type', true),
				'_siteseo_redirections_param' => get_post_meta($post->ID, '_seopress_redirections_param', true),
				'_siteseo_redirections_logged_status' => get_post_meta($post->ID, '_seopress_redirections_logged_status', true),
				'_siteseo_redirections_enabled_regex' => get_post_meta($post->ID, '_seopress_redirections_enabled_regex', true),
	
			];

			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();
		
		foreach($taxonomies as $taxonomy){
			$terms = get_terms([
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]);
			
			foreach($terms as $term){
				
				$robots_index = get_term_meta($term->term_id, '_seopress_robots_index', true);
				$robots_follow = get_term_meta($term->term_id, '_seopress_robots_follow', true);
				$robots_imageindex = get_term_meta($term->term_id, '_seopress_robots_imageindex', true);
				$robots_archive = get_term_meta($term->term_id, '_seopress_robots_archive', true);
				
				$meta_mapping = [
					'_siteseo_titles_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_titles_title', true)),
					'_siteseo_titles_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_titles_desc', true)),
					'_siteseo_social_fb_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_social_fb_title', true)),
					'_siteseo_social_fb_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_social_fb_desc', true)),
					'_siteseo_social_fb_img' => get_term_meta($term->term_id,'_seopress_social_fb_img',true),
					'_siteseo_social_twitter_title' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_social_twitter_title', true)),
					'_siteseo_social_twitter_desc' => str_replace('%%wc_single_price_exc_tax%%', '%%wc_single_price_exe_tax%%', get_term_meta($term->term_id, '_seopress_social_twitter_desc', true)),
					'_siteseo_social_twitter_img' => get_term_meta($term->term_id, '_seopress_social_twitter_img', true),
					'_siteseo_robots_index' => (!empty($robots_index) && $robots_index === 'yes') ? '1' : '0',
					'_siteseo_robots_follow' => (!empty($robots_follow) && $robots_follow === 'yes') ? '1' : '0',
					'_siteseo_robots_imageindex' => (!empty($robots_imageindex) && $robots_imageindex === 'yes') ? '1' : '0',
					'_siteseo_robots_archive' => (!empty($robots_archive) && $robots_archive === 'yes') ? '1' : '0',
					'_siteseo_robots_snippet' => get_term_meta($term->term_id, '_seopress_robots_snippet', true),
					'_siteseo_robots_canonical' => get_term_meta($term->term_id, '_seopress_robots_canonical', true),
					'_siteseo_analysis_target_kw' => get_term_meta($term->term_id, '_seopress_analysis_target_kw', true),
					'_siteseo_redirections_enabled' => get_term_meta($term->term_id, '_seopress_redirections_enabled', true) ? '1' : '0',
					'_siteseo_redirections_value' => get_term_meta($term->term_id, '_seopress_redirections_value', true),
					'_siteseo_redirections_type' => get_term_meta($term->term_id, '_seopress_redirections_type', true),
					'_siteseo_redirections_param' => get_term_meta($term->term_id, '_seopress_redirections_param', true),
					'_siteseo_redirections_logged_status' => get_term_meta($term->term_id, '_seopress_redirections_logged_status', true),
					'_siteseo_redirections_enabled_regex' => get_term_meta($term->term_id, '_seopress_redirections_enabled_regex', true),
		
				];
				
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term->term_id}";
			}
		}

		return [
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('SEOPress migration completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}
	
	static function slim_seo(){
		$imported_count = 0;
		$log = [];
		
		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		
		foreach($posts as $post){
			$post_data = get_post_meta($post->ID, 'slim_seo', true);
			
			if(empty($post_data) || !is_array($post_data)){
				continue;
			}
			
			$meta_mapping = [
				'_siteseo_titles_title' => self::replace_snippet_vars((!empty($post_data['title']) ? $post_data['title'] : ''),'slim_seo'),
				'_siteseo_titles_desc' => self::replace_snippet_vars((!empty($post_data['description']) ? $post_data['description'] : ''),'slim_seo'),
				'_siteseo_social_fb_img' => !empty($post_data['facebook_image']) ? $post_data['facebook_image'] : '',
				'_siteseo_social_twitter_img' => !empty($post_data['twitter_image']) ? $post_data['twitter_image'] : '',
				'_siteseo_robots_index'         => isset($post_data['noindex']) && $post_data['noindex'] ? '1' : '',
				'_siteseo_robots_canonical' => !empty($post_data['canonical']) ? $post_data['canonical'] : '',
			];
			
			foreach($meta_mapping as $siteseo_key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $siteseo_key, $value);
					$imported_count++;
				}
			}
			
			$log[] = "Imported post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();
		
		foreach($taxonomies as $taxonomy){
			
			$terms = get_terms([
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]);
        
			foreach($terms as $term){
				$term_data = get_term_meta($term->term_id, 'slim_seo', true);
				
				if(empty($term_data) || !is_array($term_data)){
					continue;
				}
				
				$meta_mapping = [
					'_siteseo_titles_title' => self::replace_snippet_vars((!empty($term_data['title']) ? $term_data['title'] : ''),'slim_seo'),
					'_siteseo_titles_desc' => self::replace_snippet_vars((!empty($term_data['description']) ? $term_data['description'] : ''),'slim_seo'),
					'_siteseo_social_fb_img' => !empty($term_data['facebook_image']) ? $term_data['facebook_image'] : '',
					'_siteseo_social_twitter_img' => !empty($term_data['twitter_image']) ? $term_data['twitter_image'] : '',
					'_siteseo_robots_index' => !empty($term_data['noindex']) ? true : '',
					'_siteseo_robots_canonical' => !empty($term_data['canonical']) ? $term_data['canonical'] : '',
				];
				
				foreach($meta_mapping as $siteseo_key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $siteseo_key, $value);
						$imported_count++;
					}
				}
				
				$log[] = "Imported term ID: {$term->term_id}";
			}
		}
		
		return [
			'count' => $imported_count,
			'log' => $log,
			/* translators: %d count of items imported */
			'message' => sprintf(__('Slim SEO import completed. Imported %d items.', 'siteseo'), $imported_count)
		];
	}

	static function replace_snippet_vars($string, $plugin){
		if(empty($string)) return $string;
		
		// We should not process the string if it does not have a variable
		if(!preg_match('/%|{|#/', $string)){
			return $string;
		}

		static $plugins = [
			'rank_math' => [
				'%sep%' => '%%sep%%',
				'%sitename%' => '%%sitetitle%%',
				'%sitedesc%' => '%%tagline%%',
				'%title%' => '%%post_title%%',
				'%excerpt%' => '%%post_excerpt%%',
				'%excerpt_only%' => '%%post_excerpt%%',
				'%post_thumbnail%' => '%%post_thumbnail_url%%',
				'%url%' => '%%post_url%%',
				'%date%' => '%%post_date%%',
				'%modified%' => '%%post_modified_date%%',
				'%name%' => '%%post_author%%',
				'%category%' => '%%post_category%%',
				'%tag%' => '%%post_tag%%',
				'%term%' => '%%term_title%%',
				'%term_description%' => '%%term_description%%',
				'%search_query%' => '%%search_keywords%%',
				'%pagenumber%' => '%%current_pagination%%',
				'%page%' => '%%page%%',
				'%archive_title%' => '%%archive_title%%',
				'%sitename_with_sep%' => '%%sep%%%%sitetitle%%',
				'%pt_plural%' => '%%cpt_plural%%',
				'%wc_shortdesc%' => '%%wc_single_short_desc%%',
				'%wc_price%' => '%%wc_single_price%%',
				'%wc_sku%' => '%%wc_sku%%',
				'%currentday%' => '%%currentday%%',
				'%currentmonth%' => '%%currentmonth%%',
				'%currentyear%' => '%%currentyear%%',
				'%currentdate%' => '%%currentdate%%',
				'%currenttime%' => '%%currenttime%%',
				'%user_description%' => '%%author_bio%%',
				'%focuskw%' => '%%target_keyword%%'
			],
			'yoast_seo' => [
				'%%sitename%%' => '%%sitetitle%%',
				'%%sitedesc%%' => '%%tagline%%',
				'%%title%%' => '%%post_title%%',
				'%%excerpt%%' => '%%post_excerpt%%',
				'%%excerpt_only%%' => '%%post_excerpt%%',
				'%%content%%' => '%%post_content%%',
				'%%thumbnail%%' => '%%post_thumbnail_url%%',
				'%%url%%' => '%%post_url%%',
				'%%date%%' => '%%post_date%%',
				'%%modified%%' => '%%post_modified_date%%',
				'%%author%%' => '%%post_author%%',
				'%%category%%' => '%%post_category%%',
				'%%primary_category%%' => '%%post_category%%',
				'%%tag%%' => '%%post_tag%%',
				'%%category_description%%' => '%%_category_description%%',
				'%%searchphrase%%' => '%%search_keywords%%',
				'%%pagenumber%%' => '%%current_pagination%%',
				'%%year%%' => '%%currentyear%%',
				'%%month%%' => '%%currentmonth%%',
				'%%day%%' => '%%currentday%%',
				'%%author_firstname%%' => '%%author_first_name%%',
				'%%author_lastname%%' => '%%author_last_name%%',
				'%%author_description%%' => '%%author_bio%%',
				'%%product_sku%%' => '%%wc_sku%%',
				'%%product_price%%' => '%%wc_single_price%%',
				'%%product_shortdesc%%' => '%%wc_single_short_desc%%',
				'%%product_category%%' => '%%wc_single_cat%%',
				'%%product_tag%%' => '%%wc_single_tag%%'
			],
			'aio_seo' => [
				'#separator_sa' => '%%sep%%',
				'#site_title' => '%%sitetitle%%',
				'#tagline' => '%%tagline%%',
				'#post_title' => '%%post_title%%',
				'#post_excerpt' => '%%post_excerpt%%',
				'#post_content' => '%%post_content%%',
				'#post_thumbnail' => '%%post_thumbnail_url%%',
				'#post_url' => '%%post_url%%',
				'#post_date' => '%%post_date%%',
				'#post_modified_date' => '%%post_modified_date%%',
				'#categories' => '%%post_category%%',
				'#post_tags' => '%%post_tag%%',
				'#author_name' => '%%post_author%%',
				'#taxonomy_title' => '%%post_category%%',
				'#tag_title' => '%%post_tag%%',
				'#term_name' => '%%term_title%%',
				'#term_description' => '%%term_description%%',
				'#search_query' => '%%search_keywords%%',
				'#page_number' => '%%page%%',
				'#pt_plural' => '%%cpt_plural%%',
				'#wc_short_description' => '%%wc_single_short_desc%%',
				'#wc_price' => '%%wc_single_price%%',
				'#wc_sku' => '%%wc_sku%%',
				'#current_day' => '%%currentday%%',
				'#current_month' => '%%currentmonth%%',
				'#current_year' => '%%currentyear%%',
				'#current_date' => '%%currentdate%%',
				'#current_time' => '%%currenttime%%',
				'#author_first_name' => '%%author_first_name%%',
				'#author_last_name' => '%%author_last_name%%',
				'#author_description' => '%%author_bio%%',
				'#focus_keyword' => '%%target_keyword%%',
				'#custom_field' => '%%_cf_your_custom_field_name%%'
			],
			'slim_seo' => [
				'{{ sep }}' => '%%sep%%',
				'{{ site.title }}' => '%%sitetitle%%',
				'{{ post.title }}' => '%%post_title%%',
				'{{ post.excerpt }}' => '%%post_excerpt%%',
				'{{ post.content }}' => '%%post_content%%',
				'{{ post_type.plural }}' => '%%cpt_plural%%',
				'{{ post.thumbnail }}' => '%%post_thumbnail_url%%',
				'{{ post.url }}' => '%%post_url%%',
				'{{ post.date }}' => '%%post_date%%',
				'{{ post.modified_date }}' => '%%post_modified_date%%',
				'{{ author.display_name }}' => '%%post_author%%',
				'{{ post.categories }}' => '%%post_category%%',
				'{{ post.tags }}' => '%%post_tag%%',
				'{{ term.name }}' => '%%term_title%%',
				'{{ term.description }}' => '%%term_description%%',
				'{{ page }}' => '%%page%%',
				'{{ current.month }}' => '%%currentmonth%%',
				'{{ current.day }}' => '%%currentday%%',
				'{{ current.year }}' => '%%currentyear%%',
				'{{ author.first_name }}' => '%%author_first_name%%',
				'{{ author.last_name }}' => '%%author_last_name%%',
				'{{ author.website_url }}' => '%%author_website%%',
				'{{ author.nickname }}' => '%%author_nickname%%',
				'{{ author.description }}' => '%%author_bio%%'
			],
			'surerank' => [
				'%site_name%'=> '%%sitetitle%%',
				'%title%' => '%%post_title%%',
				'%tagline%' => '%%tagline%%',
				'%post_url%' => '%%post_url%%',
				'%content%' => '%%post_content%%',
				'%sep%' => '%%sep%%',
				'%excerpt%' => '%%post_excerpt%%',
				'%author_name%' => '%%post_author%%',
				'%category%' => '%%post_category%%',
				'%tag%' => '%%post_tag%%',
				'%term_title%' => '%%term_title%%',
				'%term_description%' => '%%term_description%%',
				'%modified%' => '%%post_modified_date%%',
				'%currentdate%' => '%%currentday%%',
				'%currentmonth%' => '%%currentmonth%%',
				'%currentyear%' => '%%currentyear%%',
				
			]
		];

		if(!empty($plugins[$plugin])){
			return str_replace(array_keys($plugins[$plugin]), array_values($plugins[$plugin]), $string);
		}

		return $string;
	}

	static function surerank(){

		$imported_count = 0;
		$log = [];

		$posts = get_posts(['posts_per_page' => -1, 'post_type' => 'any', 'post_status' => 'any']);
		foreach($posts as $post){

			$general = get_post_meta($post->ID, 'surerank_settings_general', true);
			$general = is_array($general) ? $general : [];
			$social = get_post_meta($post->ID, 'surerank_settings_social', true);
			$social = is_array($social) ? $social : [];
			$noindex = get_post_meta($post->ID, 'surerank_settings_post_no_index', true);
			$nofollow = get_post_meta($post->ID, 'surerank_settings_post_no_follow', true);
			$noarchive = get_post_meta($post->ID, 'surerank_settings_post_no_archive', true);

			$meta_mapping = [

				'_siteseo_titles_title' => !empty($general['page_title']) ? self::replace_snippet_vars($general['page_title'], 'surerank') : '',
				'_siteseo_titles_desc' => !empty($general['page_description']) ? self::replace_snippet_vars($general['page_description'], 'surerank') : '',
				'_siteseo_robots_canonical' => !empty($general['canonical_url']) ? $general['canonical_url'] : '',
				'_siteseo_social_fb_title' => !empty($social['facebook_title']) ? self::replace_snippet_vars($social['facebook_title'], 'surerank') : '',
				'_siteseo_social_fb_desc' => !empty($social['facebook_description']) ? self::replace_snippet_vars($social['facebook_description'], 'surerank') : '',			
				'_siteseo_social_twitter_title' => !empty($social['twitter_title']) ? self::replace_snippet_vars($social['twitter_title'], 'surerank') : '',
				'_siteseo_social_twitter_desc' => !empty($social['twitter_description']) ? self::replace_snippet_vars($social['twitter_description'], 'surerank') : '',
				'_siteseo_social_fb_img' => !empty($social['facebook_image_url']) ? $social['facebook_image_url'] : '',
				'_siteseo_social_twitter_img' => !empty($social['twitter_image_url']) ? $social['twitter_image_url'] : '',

				// Robots
				'_siteseo_robots_index' => ($noindex === 'yes')   ? '1' : '',
				'_siteseo_robots_follow' => ($nofollow === 'yes')  ? '1' : '',
				'_siteseo_robots_archive' => ($noarchive === 'yes') ? '1' : '',
			];

			foreach($meta_mapping as $key => $value){
				if(!empty($value)){
					update_post_meta($post->ID, $key, $value);
					$imported_count++;
				}
			}

			$log[] = "Imported SureRank post ID: {$post->ID}";
		}
		
		$taxonomies = get_taxonomies();

		foreach($taxonomies as $taxonomy){

			$terms = get_terms([
				'taxonomy'   => $taxonomy,
				'hide_empty' => false,
			]);

			if(is_wp_error($terms) || empty($terms)){
				continue;
			}

			foreach($terms as $term){

				$general = get_term_meta($term->term_id, 'surerank_settings_general', true);
				$general = is_array($general) ? $general : [];
				$social = get_term_meta($term->term_id, 'surerank_settings_social', true);
				$social = is_array($social) ? $social : [];
				$noindex = get_term_meta($term->term_id, 'surerank_settings_term_no_index', true);
				$nofollow = get_term_meta($term->term_id, 'surerank_settings_term_no_follow', true);
				$noarchive = get_term_meta($term->term_id, 'surerank_settings_term_no_archive', true);

				$meta_mapping = [

					// Titles
					'_siteseo_titles_title' => !empty($general['page_title']) ? self::replace_snippet_vars($general['page_title'], 'surerank') : '',
					'_siteseo_titles_desc' => !empty($general['page_description']) ? self::replace_snippet_vars($general['page_description'], 'surerank') : '',
					'_siteseo_robots_canonical' => !empty($general['canonical_url']) ? $general['canonical_url'] : '',
					'_siteseo_social_fb_title' => !empty($social['facebook_title']) ? self::replace_snippet_vars($social['facebook_title'], 'surerank') : '',
					'_siteseo_social_fb_desc' => !empty($social['facebook_description']) ? self::replace_snippet_vars($social['facebook_description'], 'surerank') : '',
					'_siteseo_social_twitter_title' => !empty($social['twitter_title']) ? self::replace_snippet_vars($social['twitter_title'], 'surerank') : '',
					'_siteseo_social_twitter_desc' => !empty($social['twitter_description']) ? self::replace_snippet_vars($social['twitter_description'], 'surerank') : '',
					'_siteseo_social_fb_img' => !empty($social['facebook_image_url']) ? $social['facebook_image_url'] : '',
					'_siteseo_social_twitter_img' => !empty($social['twitter_image_url']) ? $social['twitter_image_url'] : '',

					// Robots
					'_siteseo_robots_index'   => ($noindex === 'yes')   ? '1' : '',
					'_siteseo_robots_follow'  => ($nofollow === 'yes')  ? '1' : '',
					'_siteseo_robots_archive' => ($noarchive === 'yes') ? '1' : '',
				];

				foreach($meta_mapping as $key => $value){
					if(!empty($value)){
						update_term_meta($term->term_id, $key, $value);
						$imported_count++;
					}
				}

				$log[] = "Imported SureRank term ID: {$term->term_id}";
			}
		}

		return [
			'count' => $imported_count,
			'log' => $log,
			'message' => sprintf(__('SureRank import completed. Imported %d items.', 'siteseo'), $imported_count),
		];
	}
}
primarycategory.php000064400000005151151526415240010505 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class PrimaryCategory{
	
	static function wc_primary_category($none_terms, $terms, $post){
		$primary_cat = null;

		if(!empty($post)){
			$wc_primary_cat = get_post_meta($post->ID, '_siteseo_robots_primary_cat', true);
			if(isset($wc_primary_cat) && '' != $wc_primary_cat && 'none' != $wc_primary_cat){
				
				if(null != $post->post_type && 'product' == $post->post_type){
					$primary_cat = get_term($wc_primary_cat, 'product_cat');
				}
				
				if(!is_wp_error($primary_cat) && null != $primary_cat){
					return $primary_cat;
				}
			} else{
				return $none_terms;
			}
		} else{
			return $none_terms;
		}
	}

	static function add_primary_category($none_cate, $cats, $post){
		$primary_cat = null;

		if(!empty($post)){
			$robots_primary_cat = get_post_meta($post->ID, '_siteseo_robots_primary_cat', true);
			if(isset($robots_primary_cat) && '' != $robots_primary_cat && 'none' != $robots_primary_cat){
				
				if(null != $post->post_type && 'post' == $post->post_type){
					$primary_cat = get_category($robots_primary_cat);
				}
				
				if(!is_wp_error($primary_cat) && null != $primary_cat){
					return $primary_cat;
				}
			} else{
				return $none_cate;
			}
		} else{
			return $none_cate;
		}
	}
	
	static function replace_breadcrumb_categories($crumbs, $breadcrumb){
		if(!is_product()){
			return $crumbs;
		}

		global $post;
		$primary_cat_id = get_post_meta($post->ID, '_siteseo_robots_primary_cat', true);
		
		if(!empty($primary_cat_id) && $primary_cat_id !== 'none'){
			$primary_cat = get_term($primary_cat_id, 'product_cat');
			
			if(!empty($primary_cat) && !is_wp_error($primary_cat)){
				
				$new_crumbs = [];
				foreach($crumbs as $key => $crumb){
					
					if($key === 0 || (isset($crumb[1]) && strpos($crumb[1], '?post_type=product') !== false)){
						$new_crumbs[] = $crumb;
					}
				}
				
				$ancestors = get_ancestors($primary_cat->term_id, 'product_cat');
				$ancestors = array_reverse($ancestors);
				
				foreach($ancestors as $ancestor_id){
					$ancestor = get_term($ancestor_id, 'product_cat');
					if(!empty($ancestor) && !is_wp_error($ancestor)){
						$new_crumbs[] = [
							$ancestor->name,
							get_term_link($ancestor)
						];
					}
				}
				
				if(!empty($primary_cat) && !is_wp_error($primary_cat)){
					$new_crumbs[] = [
						$primary_cat->name,
						get_term_link($primary_cat)
					];
				}
				
				if(count($crumbs) > 0){
					$new_crumbs[] = $crumbs[count($crumbs) - 1];
				}
				
				return $new_crumbs;
			}
		}

		return $crumbs;
	}
}advanced.php000064400000015554151526415240007041 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Advanced{
	
	static function tags(){
		global $siteseo;

		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return; // toggle disable
		}
		// meta tags
		if(!empty($siteseo->advanced_settings['advanced_google'])){
			echo '<meta name="google-site-verification" content="'.esc_attr($siteseo->advanced_settings['advanced_google']).'" />' . "\n";
		}

		if(!empty($siteseo->advanced_settings['advanced_bing'])){
			echo '<meta name="msvalidate.01" content="'.esc_attr($siteseo->advanced_settings['advanced_bing']).'" />' . "\n";
		}

		if(!empty($siteseo->advanced_settings['advanced_pinterest'])){
			echo '<meta name="p:domain_verify" content="'.esc_attr($siteseo->advanced_settings['advanced_pinterest']).'" />';
		}

		if(!empty($siteseo->advanced_settings['advanced_yandex'])){
			echo '<meta name="yandex-verification" content="'.esc_attr($siteseo->advanced_settings['advanced_yandex']).'" />';
		}

		if(!empty($siteseo->advanced_settings['advanced_wp_rsd'])){
			remove_action('wp_head', 'rsd_link');
		}

	}
	
	static function remove_links(){
		global $siteseo;

		if(empty($siteseo->setting_enabled['toggle-advanced'])){
			return; // toggle disable
		}

		if(!empty($siteseo->advanced_settings['advanced_wp_rsd'])){
			remove_action('wp_head', 'rsd_link');
		}

		if(!empty($siteseo->advanced_settings['advanced_wp_wlw'])){
			remove_action('wp_head', 'wlwmanifest_link');
		}

		if(!empty($siteseo->advanced_settings['advanced_wp_shortlink'])){
			remove_action('wp_head', 'wp_shortlink_wp_head');
		}

		if(!empty($siteseo->advanced_settings['advanced_wp_generator'])){
			remove_action('wp_head', 'wp_generator');
		}

		if(!empty($siteseo->advanced_settings['advanced_comments_form_link'])){
			add_filter('comment_form_default_fields', '\SiteSEO\Advanced::remove_comment_url_field');
		}

		if(!empty($siteseo->advanced_settings['advanced_comments_author_url'])){
			add_filter('get_comment_author_link', '\SiteSEO\Advanced::remove_author_link_if_profile_url');
		}

		if(!empty($siteseo->advanced_settings['advanced_hentry'])){
			add_filter('post_class', '\SiteSEO\Advanced::remove_hentry_post_class');
		}

		if(!empty($siteseo->advanced_settings['advanced_noreferrer'])){
			add_filter('the_content', '\SiteSEO\Advanced::remove_noreferrer_from_post_content');
		}

		if(!empty($siteseo->advanced_settings['advanced_tax_desc_editor'])){
			add_action('edit_term', '\SiteSEO\Advanced::add_wp_editor_to_taxonomy_description', 10, 2);
		}
		
		if(!empty($siteseo->advanced_settings['advanced_category_url'])){
			add_action('init', '\SiteSEO\Advanced::remove_category_base', 111);
			add_action('template_redirect', '\SiteSEO\Advanced::redirect_category');
		}
	}
	
	static function add_wp_editor_to_taxonomy_description($tag, $tt_id = 0){

		if('edit' !== get_current_screen()->base || 'edit-tags' !== get_current_screen()->id){
			return;
		}

		if(isset($tag->description)){
			$editor_settings = array(
				'textarea_name' => 'description',
				'textarea_rows' => 10,
				'editor_class' => 'wp-editor-area',
				'media_buttons' => true,
				'tinymce' => true,
				'quicktags' => true,
			);

			wp_editor($tag->description, 'description', $editor_settings);
		}
	}

	static function remove_noreferrer_from_post_content($content){
		$content = preg_replace('/(<a\s+[^>]*rel=["\'][^"\']*?)(\s*\bnoreferrer\b\s*)([^"\']*["\'][^>]*>)/i', '$1$3', $content);
		return $content;
	}

	static function remove_hentry_post_class($classes){
		$classes = array_diff($classes, array('hentry'));
		return $classes;
	}

	static function remove_comment_url_field($fields){
		if(isset($fields['url'])){
			unset($fields['url']);
		}

		return $fields;
	}

	static function remove_author_link_if_profile_url($comment_author_link = '', $comment_author = '', $comment_id = 0){
		if(empty($comment_id)){
			return $comment_author;
		}

		$comment = get_comment($comment_id);
		
		if(empty($comment) || !is_object($comment)){
			return $comment_author;
		}

		$user_id = $comment->user_id;

		if(!empty($user_id)){
			$user_website = get_the_author_meta('user_url', $user_id);

			if($user_website){
				return get_comment_author($comment_id);
			}
		}

		return $comment_author;
	}
	
	static function remove_category_base(){
		
		$categories = get_categories(array('hide_empty' => false));
		$category_slugs = wp_list_pluck($categories, 'slug');

		if(empty($category_slugs)){
			return;
		}
    
		$category_pattern = '(' . implode('|', $category_slugs) .')';
    
		add_rewrite_rule(
			'^'.$category_pattern.'/?$',
			'index.php?category_name=$matches[1]',
			'top'
		);
		
		// Add rule for handle pagination  
		add_rewrite_rule(
			'^'.$category_pattern.'/page/([0-9]+)/?$',
			'index.php?category_name=$matches[1]&paged=$matches[2]',
			'top'
		);
	}
	
	static function redirect_category(){
		if(is_category() && !is_admin()){
			$category = get_query_var('category_name');
			$category_base = get_option('category_base');
			$base_to_check = !empty($category_base) ? $category_base : 'category';

			if(!empty($category) && strpos(sanitize_url($_SERVER['REQUEST_URI']), '/'.$base_to_check.'/') !== false){
				wp_safe_redirect(home_url('/' . $category . '/'), 301);
				exit;
			}
		}
	}
		
	static function remove_wc_category_base(){
		global $siteseo;

		if(empty($siteseo->advanced_settings['advanced_product_cat_url']) || empty($siteseo->setting_enabled['toggle-advanced'])){
			return;
		}
		
		if(!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))){
			return;
		}
		
		add_filter('term_link', '\SiteSEO\Advanced::remove_category_base_woo', 10, 3);
		add_filter('request', '\SiteSEO\Advanced::category_url_request');
		add_action('created_product_cat', 'flush_rewrite_rules');
		add_action('delete_product_cat', 'flush_rewrite_rules');
		add_action('edited_product_cat', 'flush_rewrite_rules');
		add_action('parse_request', '\SiteSEO\Advanced::old_category_url_request');
		
	}
	
	static function remove_category_base_woo($termlink, $term, $taxonomy){
		if($taxonomy === 'product_cat'){
			$category_base = '/product-category/';
			return str_replace($category_base, '/', $termlink);
		}

		return $termlink;
	}
	
	static function category_url_request($query_vars){
		if(!isset($query_vars['product_cat']) && isset($query_vars['pagename'])){
			$pagename = $query_vars['pagename'];
			$term = get_term_by('slug', $pagename, 'product_cat');

			if($term){
				$query_vars['product_cat'] = $term->slug;
				unset($query_vars['pagename']);
			}
		}

		return $query_vars;
	}
	
	static function old_category_url_request($wp){
		
		if(!isset($wp->query_vars['pagename'])){
			return;
		}
		
		$pagename = $wp->query_vars['pagename'];
		$term = get_term_by('slug', $pagename, 'product_cat');
		
		if($term){
			$wp->query_vars['product_cat'] = $term->slug;
			unset($wp->query_vars['pagename']);
		}
		
	}
}
titlesmetas.php000064400000100122151526415240007614 0ustar00<?php
/*
* SITESEO
* https://siteseo.io
* (c) SiteSEO Team
*/

namespace SiteSEO;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class TitlesMetas{
	
	static function advanced_metas($robots){
		global $siteseo, $post;
		
		$disable_noindex = !empty($siteseo->advanced_settings['appearance_adminbar_noindex']) ? true : '';

		if(empty($siteseo->setting_enabled['toggle-titles']) || !empty($disable_noindex)){
			return $robots;
		}
		
		$settings = $siteseo->titles_settings;
		
		//all  post types and taxonomies
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
    
		$post_id = isset($post) && is_object($post) ? $post->ID : 0;
		
		$index_extras = [
			'max-snippet' => '-1',
			'max-image-preview' => 'large',
			'max-video-preview' => '-1'
		];
		
		
		$robots = [
			'noindex' => !empty($settings['titles_noindex']),
			'nofollow' => !empty($settings['titles_nofollow']),
			'nosnippet' => !empty($settings['titles_nosnippet']),
			'noarchive' => !empty($settings['titles_noarchive']),
			'noimageindex' => !empty($settings['titles_noimageindex'])
		];

		if(!empty($post_id) && !empty($post->post_password)){
			$robots['noindex'] = true;
		}
		
		foreach($taxonomies as $taxonomy){
			// taxonomies
			$term_id = 0;
			if(is_tax() || is_category() || is_tag()){
				$queried_object = get_queried_object();
				$term_id = $queried_object->term_id ? $queried_object->term_id : 0;
				
				if($term_id){
					$robots['noindex'] = !empty(get_term_meta($term_id, '_siteseo_robots_index', true)) || $robots['noindex'];
					$robots['nofollow'] = !empty(get_term_meta($term_id, '_siteseo_robots_follow', true)) || $robots['nofollow'];
					$robots['nosnippet'] = !empty(get_term_meta($term_id, '_siteseo_robots_snippet', true)) || $robots['nosnippet'];
					$robots['noarchive'] = !empty(get_term_meta($term_id, '_siteseo_robots_archive', true)) || $robots['noarchive'];
					$robots['noimageindex'] = !empty(get_term_meta($term_id, '_siteseo_robots_imageindex', true)) || $robots['noimageindex'];
				}
				
				
				if(!empty($settings['titles_tax_titles'][$taxonomy->name]['noindex'])){
					
					if(isset($robots['index'])){
						unset($robots['index']);
					}
					
					$robots['noindex'] = true;
				}
								
				if(!empty($settings['titles_tax_titles'][$taxonomy->name]['nofollow'])){
					
					if(isset($robots['follow'])){
						unset($robots['follow']);
					}
					
					$robots['nofollow'] = true;
				}

				if(!$robots['noindex']){
					$robots['index'] = true;
					$robots = array_merge($robots, $index_extras);
				}

				if(!$robots['nofollow']){
					$robots['follow'] = true;
				}

				return array_filter($robots);
			}
		}
		
		// single post types
		foreach($post_types as $post_type){
			
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				
				if(function_exists('is_shop') && is_shop()){
					$post_id = !defined('SITEPAD') ? wc_get_page_id('shop') : kkart_get_page_id('shop');
				}
				
				if($post_id){
					$robots['noindex'] = !empty(get_post_meta($post_id, '_siteseo_robots_index', true)) || $robots['noindex'];
					$robots['nofollow'] = !empty(get_post_meta($post_id, '_siteseo_robots_follow', true)) || $robots['nofollow'];
					$robots['nosnippet'] = !empty(get_post_meta($post_id, '_siteseo_robots_snippet', true)) || $robots['nosnippet'];
					$robots['noarchive'] = !empty(get_post_meta($post_id, '_siteseo_robots_archive', true)) || $robots['noarchive'];
					$robots['noimageindex'] = !empty(get_post_meta($post_id, '_siteseo_robots_imageindex', true)) || $robots['noimageindex'];
				}
							
				if(!empty($settings['titles_archive_titles'][$post_type->name]['archive_noindex'])){
					
					if(isset($robots['index'])){
						unset($robots['index']);	
					}
					
					$robots['noindex'] = true;
				}
								
				if(!empty($settings['titles_archive_titles'][$post_type->name]['archive_nofollow'])){
					
					if(isset($robots['follow'])){
						unset($robots['follow']);
					}
					
					$robots['nofollow'] = true;
				}


				if(!$robots['noindex']){
					$robots['index'] = true;
					$robots = array_merge($robots, $index_extras);
				}

				if(!$robots['nofollow']){
					$robots['follow'] = true;
				}

				return array_filter($robots);
				
			}
			
			if(is_singular($post_type->name)){
				
				if($post_id){
					$robots['noindex'] = !empty(get_post_meta($post_id, '_siteseo_robots_index', true)) || $robots['noindex'];
					$robots['nofollow'] = !empty(get_post_meta($post_id, '_siteseo_robots_follow', true)) || $robots['nofollow'];
					$robots['nosnippet'] = !empty(get_post_meta($post_id, '_siteseo_robots_snippet', true)) || $robots['nosnippet'];
					$robots['noarchive'] = !empty(get_post_meta($post_id, '_siteseo_robots_archive', true)) || $robots['noarchive'];
					$robots['noimageindex'] = !empty(get_post_meta($post_id, '_siteseo_robots_imageindex', true)) || $robots['noimageindex'];
				}
							
				if(!empty($settings['titles_single_titles'][$post_type->name]['noindex'])){
					
					if(isset($robots['index'])){
						unset($robots['index']);	
					}
					
					$robots['noindex'] = true;
				}
								
				if(!empty($settings['titles_single_titles'][$post_type->name]['nofollow'])){
					
					if(isset($robots['follow'])){
						unset($robots['follow']);
					}
					
					$robots['nofollow'] = true;
				}


				if(!$robots['noindex']){
					$robots['index'] = true;
					$robots = array_merge($robots, $index_extras);
				}

				if(!$robots['nofollow']){
					$robots['follow'] = true;
				}
				
				// woocommerce pages, cart page
				if(function_exists('is_cart') && is_cart()){
					unset($robots['index']);
					$robots['noindex'] = true;
				}
				
				// checkout page
				if(function_exists('is_checkout') && is_checkout()){
					unset($robots['index']);
					$robots['noindex'] = true;
				}
				
				// account page 
				if(function_exists('is_account_page') && is_account_page()){
					unset($robots['index']);
					$robots['noindex'] = true;
				}

				return array_filter($robots);
			}
		}
		
		//archive pages
		if(is_author()){
			$robots['noindex'] = !empty($settings['titles_archives_author_noindex']);
			
			if(!$robots['noindex']){
				$robots['index'] = true;
				$robots = array_merge($robots, $index_extras);
			}
		}
		
		if(is_date()){
			$robots['noindex'] = !empty($settings['titles_archives_date_noindex']);
			
			if(!$robots['noindex']){
				$robots['index'] = true;
				$robots = array_merge($robots, $index_extras);
			}
		}
		
		if(is_search()){
			$robots['noindex'] = !empty($settings['titles_archives_search_title_noindex']);
			
			if(!$robots['noindex']){
				$robots['index'] = true;
				$robots = array_merge($robots, $index_extras);
			}
		}

		// default home page
		if(is_front_page() && is_home()){

			$robots = [
				'index' => true,
				'follow' => true
			];

			if(!empty($settings['titles_noindex'])){
				$robots['noindex'] = true;
				unset($robots['index']);
			}

			if(!empty($settings['titles_nofollow'])){
				$robots['nofollow'] = true;
				unset($robots['follow']);
			}

			if(!empty($settings['titles_nosnippet'])){
				$robots['nosnippet'] = true;
			}

			if(!empty($settings['titles_noarchive'])){
				$robots['noarchive'] = true;
			}

			if(!empty($settings['titles_noimageindex'])){
				$robots['noimageindex'] = true;
			}

			$robots = array_merge($robots, $index_extras);
		}
		
		// static set posts page
		if(is_home() && !is_front_page()){
			$blog_page_id = get_option('page_for_posts');
			
			$robots = [
				'index' => true,
				'follow' => true
			];
			
			if($blog_page_id){
				// Check blog page specific meta settings
				$robots['noindex'] = !empty(get_post_meta($blog_page_id, '_siteseo_robots_index', true));
				$robots['nofollow'] = !empty(get_post_meta($blog_page_id, '_siteseo_robots_follow', true));
				$robots['nosnippet'] = !empty(get_post_meta($blog_page_id, '_siteseo_robots_snippet', true));
				$robots['noarchive'] = !empty(get_post_meta($blog_page_id, '_siteseo_robots_archive', true));
				$robots['noimageindex'] = !empty(get_post_meta($blog_page_id, '_siteseo_robots_imageindex', true));
			}
			
			// Apply global settings as fallback
			if(!empty($settings['titles_noindex'])){
				$robots['noindex'] = true;
			}

			if(!empty($settings['titles_nofollow'])){
				$robots['nofollow'] = true;
			}

			if(!empty($settings['titles_nosnippet'])){
				$robots['nosnippet'] = true;
			}

			if(!empty($settings['titles_noarchive'])){
				$robots['noarchive'] = true;
			}

			if(!empty($settings['titles_noimageindex'])){
				$robots['noimageindex'] = true;
			}
			
			// Clean up conflicting directives
			if(!empty($robots['noindex'])){
				unset($robots['index']);
			}
			
			if(!empty($robots['nofollow'])){
				unset($robots['follow']);
			}
			
			if(empty($robots['noindex'])){
				$robots = array_merge($robots, $index_extras);
			}
		}
		
		return array_filter($robots);
	}
	
	static function add_nositelinkssearchbox(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-titles'])){
			return;
		}
	
		if(!empty($siteseo->titles_settings['titles_nositelinkssearchbox'])){
			echo '<meta name="google" content="nositelinkssearchbox" >';
		}
		
	}
	
	static function add_canonical_url(){	
		$post_types = siteseo_post_types();
		
		foreach($post_types as $post_type){
			
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				$post_id = get_the_ID();
				$archive_url = get_post_type_archive_link($post_type->name);
				$canonical_meta = get_post_meta($post_id, '_siteseo_robots_canonical', true);
				$canonical = !empty($canonical_meta) ? $canonical_meta : $archive_url;
				
				if($archive_url){
					echo '<link rel="canonical" href="'.esc_url($archive_url).'" />' . "\n";
				}
			}
			
			if(is_singular($post_type->name)){
				$post_id = get_the_ID();
				$canonical_meta = get_post_meta($post_id, '_siteseo_robots_canonical', true);
				$canonical = !empty($canonical_meta) ? $canonical_meta : urldecode(get_permalink($post_id));
				
				if($canonical){
					echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";
				}
			}
		}

		//taxonomies
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		
		if(is_tag() || is_category() || is_tax()){
			$term = get_queried_object();
			if($term && isset($term->term_id, $term->taxonomy)){
				$term_id = $term->term_id;
				$taxonomy_name = $term->taxonomy;
				
				$canonical_meta = get_term_meta($term_id, '_siteseo_robots_canonical', true);
				$canonical = !empty($canonical_meta) ? $canonical_meta : urldecode(get_term_link($term_id, $taxonomy_name));
				
				if($canonical){
					echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";
				}
			}
		}
		
		// default home page
		if(is_front_page() && is_home()){
			$canonical = trailingslashit(home_url());
			echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";				
		}
		
		// if static posts set
		if(is_home() && !is_front_page()){ 
			$blog_page_id = get_option('page_for_posts');
			if($blog_page_id){
				$canonical_meta = get_post_meta($blog_page_id, '_siteseo_robots_canonical', true);
				$canonical = !empty($canonical_meta) ? $canonical_meta : urldecode(get_permalink($blog_page_id));
				
				if($canonical){
					echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";
				}
			} else{
				$canonical = trailingslashit(home_url());
				echo '<link rel="canonical" href="'.esc_url($canonical).'" />' . "\n";
			}
		}
		 
	}
	
	static function replace_variables($content, $in_editor = false){
		global $post, $siteseo, $wp_query, $term;
		
		// Site info
		$site_title = get_bloginfo('name');
		$site_tagline = get_bloginfo('description');
		$site_sep = !empty($siteseo->titles_settings['titles_sep']) ? $siteseo->titles_settings['titles_sep'] : '-';

		$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
		$page = get_query_var('page') ? get_query_var('page') : 1;
		
		// Date info
		$current_time = current_time('timestamp');
		$archive_date = get_the_date('d');
		$archive_month = get_the_date('M');
		$archive_month_name = get_the_date('F');
		$archive_year = get_the_date('Y');
		
		// Author
		$author_id = isset($post->post_author) ? $post->post_author : get_current_user_id();
		$author_first_name = get_the_author_meta('first_name', $author_id);
		$author_last_name = get_the_author_meta('last_name', $author_id);
		$author_website = get_the_author_meta('url', $author_id);
		$author_nickname = get_the_author_meta('nickname', $author_id);
		$author_bio = get_the_author_meta('description', $author_id);
		
		// WooCommerce
		$wc_variables = [];
		if(function_exists('wc_get_product') && is_singular('product')){
			$product = wc_get_product($post->ID);
			if($product){
				$wc_variables = array(
					'%%wc_single_cat%%' => wp_strip_all_tags(wc_get_product_category_list($post->ID)),
					'%%wc_single_tag%%' => wp_strip_all_tags(wc_get_product_tag_list($post->ID)),
					'%%wc_single_short_desc%%' => $product->get_short_description(),
					'%%wc_single_price%%' => $product->get_price(),
					'%%wc_single_price_exe_tax%%' => wc_get_price_excluding_tax($product),
					'%%wc_sku%%' => $product->get_sku(),
					'%%wc_parent_cat%%' => self::get_parent_category_name($post->ID),
				);
			}
		}
		
		//KKART
		$kkart_variables = [];
		if(function_exists('kkart_get_product') && is_singular('product')){
			$product = kkart_get_product($post->ID);
			if($product){
				$kkart_variables = array(
					'%%wc_single_cat%%' => wp_strip_all_tags(kkart_get_product_category_list($post->ID)),
					'%%wc_single_tag%%' => wp_strip_all_tags(kkart_get_product_tag_list($post->ID)),
					'%%wc_single_short_desc%%' => $product->get_short_description(),
					'%%wc_single_price%%' => $product->get_price(),
					'%%wc_single_price_exe_tax%%' => kkart_get_price_excluding_tax($product),
					'%%wc_sku%%' => $product->get_sku(),
					'%%wc_parent_cat%%' => self::get_parent_category_name($post->ID),
				);
			}
		}

		$replacements = array(
			'%%sep%%' => $site_sep,
			'%%sitetitle%%' => $site_title,
			'%%tagline%%' => $site_tagline,
			'%%post_title%%' => (is_singular() || $in_editor === TRUE) ? get_the_title() : (is_home() ? get_the_title(get_option('page_for_posts')) : ''),
			'%%post_excerpt%%' => (is_singular() || $in_editor === TRUE) ? get_the_excerpt() : '',
			'%%post_content%%' => (is_singular() || $in_editor === TRUE) ? wp_strip_all_tags(get_the_content()) : '',
			'%%post_thumbnail_url%%' => get_the_post_thumbnail_url($post),
			'%%post_url%%' => urldecode(get_permalink()),
			'%%post_date%%' => get_the_date(),
			'%%post_modified_date%%' => get_the_modified_date(),
			'%%post_author%%' => get_the_author(),
			'%%post_category%%' => wp_strip_all_tags(get_the_category_list(', ')),
			'%%post_tag%%' => wp_strip_all_tags(get_the_tag_list('', ', ', '')),
			'%%_category_title%%' => single_cat_title('', false),
			'%%_category_description%%' => category_description(),
			'%%tag_title%%' => single_tag_title('', false),
			'%%tag_description%%' => tag_description(),
			'%%term_title%%' => single_term_title('', false),
			'%%term_description%%' => term_description(),
			'%%search_keywords%%' => get_search_query(),
			'%%current_pagination%%' => $paged,
			'%%page%%' => $page,
			'%%cpt_plural%%' => post_type_archive_title('', false),
			'%%archive_title%%' => get_the_archive_title(),
			'%%archive_date%%' => $archive_date,
			'%%archive_date_day%%' => $archive_date,
			'%%archive_date_month%%' => $archive_month,
			'%%archive_date_month_name%%' => $archive_month_name,
			'%%archive_date_year%%' => $archive_year,
			'%%currentday%%' => date_i18n('j', $current_time),
			'%%currentmonth%%' => date_i18n('F', $current_time),
			'%%currentmonth_short%%' => date_i18n('M', $current_time),
			'%%currentmonth_num%%' => date_i18n('n', $current_time),
			'%%currentyear%%' => date_i18n('Y', $current_time),
			'%%currentdate%%' => date_i18n(get_option('date_format'), $current_time),
			'%%currenttime%%' => date_i18n(get_option('time_format'), $current_time),
			'%%author_first_name%%' => $author_first_name,
			'%%author_last_name%%' => $author_last_name,
			'%%author_website%%' => $author_website,
			'%%author_nickname%%' => $author_nickname,
			'%%author_bio%%' => $author_bio,
		);
		
		//WooCommerces
		if(!empty($wc_variables)){
			$replacements = array_merge($replacements, $wc_variables);
		}

		//Kkart
		if(!empty($kkart_variables)){
			$replacements = array_merge($replacements, $kkart_variables);
		}

		$safe_list = [
			'_siteseo_titles_title',
			'_siteseo_titles_desc',
			'_siteseo_social_fb_title',
			'_siteseo_social_fb_desc',
			'_siteseo_social_fb_img',
			'_siteseo_social_twitter_title',
			'_siteseo_social_twitter_desc',
			'_siteseo_social_twitter_img',

			// WooCommerce 
			'_price',
			'_regular_price',
			'_sale_price',
			'_stock',
			'_stock_status',
			'_sku',
			'_weight',
			'_length',
			'width',
			'_height',
			'total_sales',
		];

		if(preg_match_all('/%%_cf_(.*?)%%/', $content, $matches)){
			foreach ($matches[1] as $custom_field) {

				if(!in_array($custom_field, $safe_list, true)){
					continue;
				}

				$meta_value = get_post_meta($post->ID, $custom_field, true);
				$replacements["%%_cf_{$custom_field}%%"] = $meta_value;
			}
		}

		if(preg_match_all('/%%_ct_(.*?)%%/', $content, $matches)){
			foreach($matches[1] as $taxonomy){

				if(!in_array($taxonomy, $safe_list, true)){
					continue;
				}

				$terms = get_the_terms($post->ID, $taxonomy);
				$term_names = is_array($terms) ? wp_list_pluck($terms, 'name') : [];
				$replacements["%%_ct_{$taxonomy}%%"] = implode(', ', $term_names);
			}
		}

		if(preg_match_all('/%%_ucf_(.*?)%%/', $content, $matches)){
			foreach($matches[1] as $user_meta){

				if(!in_array($user_meta, $safe_list, true)){
					continue;
				}

				$meta_value = get_user_meta($author_id, $user_meta, true);
				$replacements["%%_ucf_{$user_meta}%%"] = $meta_value;
			}
		}

		$target_keywords = isset($siteseo->keywords_settings['tempory_set']) ? $siteseo->keywords_settings['tempory_set'] : '';
		$replacements['%%target_keyword%%'] = $target_keywords;

		$replacements = array_map(function($value){
			if(is_array($value) || is_object($value)){
				return '';
			}

			return is_null($value) ? '' : wp_strip_all_tags($value);
		}, $replacements);

		return str_replace(
			array_keys($replacements),
			array_values($replacements),
			$content
		);
	}

	static function get_parent_category_name($product_id){
		if(!class_exists('WooCommerce') && !class_exists('KKART')){
			return;
		}

		$terms = get_the_terms($product_id, 'product_cat');

		if(empty($terms) || is_wp_error($terms)){
			return '';
		}

		// Find the parent category (the one with parent = 0)
		foreach($terms as $term){
			if($term->parent == 0){
				return $term->name;
			}
		}

	}
	
	static function modify_site_title($title, $sep = ''){
		global $siteseo, $post;

		// Check enabled
		if(empty($siteseo->setting_enabled['toggle-titles'])){
			return $title;
		}

		$settings = $siteseo->titles_settings;

		// post types and taxonomies
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');
		
		// Check set by meta
		$post_id = isset($post) && is_object($post) ? $post->ID : '';
		$post_meta_title = !empty(get_post_meta($post_id, '_siteseo_titles_title', true)) ? get_post_meta($post_id, '_siteseo_titles_title', true) : '';
		
		// default home page
		if(is_front_page() && is_home()){
			
			if(!empty($settings['titles_home_site_title'])){
				$new_title = $settings['titles_home_site_title'];
			}
			
			if(!empty($new_title)){
				$new_title = esc_attr(self::replace_variables($new_title));
				if(!empty($sep)){
					$new_title .= " $sep " . get_bloginfo('name');
				}
				
				return $new_title;
			}
		}
		
		// static posts pages
		if(is_home() && !is_front_page()){
			$blog_page_id = get_option('page_for_posts');
			
			if($blog_page_id){
				$blog_meta_title = get_post_meta($blog_page_id, '_siteseo_titles_title', true);
				$default_title = !empty($settings['titles_single_titles']['page']['title']) ? $settings['titles_single_titles']['page']['title'] : '';
				
				$new_title = !empty($blog_meta_title) ? $blog_meta_title : $default_title;
				
				if(!empty($new_title)){
					$new_title = esc_attr(self::replace_variables($new_title));

					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
			}
		}

		// single post types
		foreach($post_types as $post_type){
			
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				
				$post_meta_title = '';
				
				if(function_exists('is_shop') && is_shop()){
					$shop_page_id = !defined('SITEPAD') ? wc_get_page_id('shop') : kkart_get_page_id('shop') ;
					$post_meta_title = get_post_meta($shop_page_id, '_siteseo_titles_title', true);
				}
				
				$default_title = isset($settings['titles_archive_titles'][$post_type->name]['archive_title']) ? $settings['titles_archive_titles'][$post_type->name]['archive_title'] : '';
				
				$new_title = !empty($post_meta_title) ? $post_meta_title : $default_title;

				if(!empty($new_title)){
					$new_title = esc_attr(self::replace_variables($new_title));

					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
				
			}
			
			if(is_singular($post_type->name)){
				$default_title = isset($settings['titles_single_titles'][$post_type->name]['title']) ? $settings['titles_single_titles'][$post_type->name]['title'] : '';
				$new_title = !empty($post_meta_title) ? $post_meta_title : $default_title;

				if(!empty($new_title)){
					$new_title = esc_attr(self::replace_variables($new_title));

					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
			}
		}

		//taxonomies
		foreach($taxonomies as $taxonomy){
			if(is_category()){
				$term = get_queried_object();
				$term_id = $term->term_id;
				$term_meta_title = get_term_meta($term_id, '_siteseo_titles_title', true);
				$default_title = isset($settings['titles_tax_titles']['category']['title']) ? $settings['titles_tax_titles']['category']['title'] : '';
				$disabled = !empty($settings['titles_tax_titles']['category']['disabled']);
				$new_title = !empty($term_meta_title) ? $term_meta_title : $default_title;

				if(!empty($new_title) && !$disabled){
					$new_title = esc_attr(self::replace_variables($new_title));
					
					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
			} elseif(is_tag()) {
				$term = get_queried_object();
				$term_id = $term->term_id;
				$term_meta_title = get_term_meta($term_id, '_siteseo_titles_title', true);
				$default_title = isset($settings['titles_tax_titles']['post_tag']['title']) ? $settings['titles_tax_titles']['post_tag']['title'] : '';
				$disabled = !empty($settings['titles_tax_titles']['post_tag']['disabled']);

				$new_title = !empty($term_meta_title) ? $term_meta_title : $default_title;

				if(!empty($new_title) && !$disabled){
					$new_title = esc_attr(self::replace_variables($new_title));

					
					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
			} elseif(is_tax($taxonomy->name)) {
				$term = get_queried_object();
				$term_id = $term->term_id;
				$term_meta_title = get_term_meta($term_id, '_siteseo_titles_title', true);
				$default_title = isset($settings['titles_tax_titles'][$taxonomy->name]['title']) ? $settings['titles_tax_titles'][$taxonomy->name]['title'] : '';
				$disabled = !empty($settings['titles_tax_titles'][$taxonomy->name]['disabled']);

				$new_title = !empty($term_meta_title) ? $term_meta_title : $default_title;

				if(!empty($new_title) && !$disabled){
					$new_title = esc_attr(self::replace_variables($new_title));

					if(!empty($sep)){
						$new_title .= " $sep " . get_bloginfo('name');
					}

					return $new_title;
				}
			}
		}
		
		// author archive
		if(is_author() && !empty($settings['titles_archives_author_title']) && empty($settings['titles_archives_author_disable'])) {
			$new_title = esc_attr(self::replace_variables($settings['titles_archives_author_title']));

			if(!empty($sep)){
				$new_title .= " $sep " . get_bloginfo('name');
			}

			return $new_title;
		}

		//Date archive
		if(is_date() && !empty($settings['titles_archives_date_title']) && empty($settings['titles_archives_date_disable'])){
			$new_title = esc_attr(self::replace_variables($settings['titles_archives_date_title']));

			if(!empty($sep)){
				$new_title .= " $sep " . get_bloginfo('name');
			}

			return $new_title;
		}
		
		// Search archive
		if(is_search() && !empty($settings['titles_archives_search_title'])){

			$new_title = esc_attr(self::replace_variables($settings['titles_archives_search_title']));

			if(!empty($sep)){
				$new_title .= " $sep " . get_bloginfo('name');
			}

			return $new_title;
		}
		
		// 404 archive
		if(is_404() && !empty($settings['titles_archives_404_title'])){

			$new_title = esc_attr(self::replace_variables($settings['titles_archives_404_title']));

			if(!empty($sep)){
				$new_title .= " $sep " . get_bloginfo('name');
			}

			return $new_title;
		}

		return $title;
	}
	
	static function add_meta_description(){
		global $siteseo, $post;

		if(empty($siteseo->setting_enabled['toggle-titles'])){
			return;
		}

		$settings = $siteseo->titles_settings;

		// Get all registered post types
		$post_types = siteseo_post_types();
		$taxonomies = get_taxonomies(array('public' => true), 'objects');

		$post_id = isset($post) && is_object($post) ? $post->ID : '';
		
		// default home page
		if(is_front_page() && is_home()){
			
			if(!empty($settings['titles_home_site_desc'])){
				$processed_desc = self::replace_variables($settings['titles_home_site_desc']);
				echo '<meta name="description" content="' . esc_attr(self::truncate_desc($processed_desc)) . '">';
			} else{
				$description = get_bloginfo('description');
				if(!empty($description)){
					echo '<meta name="description" content="' . esc_attr($description) . '">';
				}
			}
		}
		
		// if set static posts page
		if(is_home() && !is_front_page()){
			$blog_page_id = get_option('page_for_posts');
			if($blog_page_id){
				$meta_desc = get_post_meta($blog_page_id, '_siteseo_titles_desc', true);
				if(!empty($meta_desc)){
					$processed_desc = esc_attr(self::replace_variables($meta_desc));
					echo '<meta name="description" content="' . esc_attr(self::truncate_desc($processed_desc)) . '">';
				} elseif(!empty($settings['titles_single_titles']['page']['description'])){
					$processed_desc = self::replace_variables($settings['titles_single_titles']['page']['description']);
				
					echo '<meta name="description" content="' . esc_attr(self::truncate_desc($processed_desc)) . '">';
				} else{
					$description = get_bloginfo('description'); 
					if(!empty($description)){ 
						echo '<meta name="description" content="' . esc_attr(self::truncate_desc($description)) . '">'; 
					} 
				}
			}
		}
		
		// single post types
		foreach($post_types as $post_type){
			
			if($post_type->has_archive && is_post_type_archive($post_type->name)){
				
				$archive_desc = '';
				if(is_post_type_archive()){
					$obj = get_queried_object();
					
					if(!empty($obj) && isset($obj->name)){
						$archive_desc  = !empty($obj->description) ? $obj->description : '';
					}
				}
				
				$meta_desc = '';
				
				if(function_exists('is_shop') && is_shop()){
					$shop_page_id = !defined('SITEPAD') ? wc_get_page_id('shop') : kkart_get_page_id('shop');
					$meta_desc = get_post_meta($shop_page_id, '_siteseo_titles_desc', true);
				}
				
				$description = !empty($settings['titles_archive_titles'][$post_type->name]['archive_desc']) ? $settings['titles_archive_titles'][$post_type->name]['archive_desc'] : $archive_desc;
				
				$description = !empty($meta_desc) ? $meta_desc : $description;

				if(!empty($description)){
					$description = self::replace_variables($description);
					echo '<meta name="description" content="' . esc_attr(self::truncate_desc($description)) . '">';
				}
				
			}
			
			if(is_singular($post_type->name)){
				$meta_desc = get_post_meta($post_id, '_siteseo_titles_desc', true);
				$default_desc = isset($settings['titles_single_titles'][$post_type->name]['description']) ? $settings['titles_single_titles'][$post_type->name]['description'] : '';

				$description = !empty($meta_desc) ? $meta_desc : $default_desc;

				if(!empty($description)){
					$description = self::replace_variables($description);
					echo '<meta name="description" content="' . esc_attr(self::truncate_desc($description)) . '">';
				}
			}
		}
		
		if(is_category() || is_tag() || is_tax()){
			$term = get_queried_object();
			if($term){
				$term_id = $term->term_id;
				$term_meta_desc = get_term_meta($term_id, '_siteseo_titles_desc', true);
				$default_desc = '';
				$taxonomy_name = '';

				if(is_category()){
					$default_desc = isset($settings['titles_tax_titles']['category']['description']) ? $settings['titles_tax_titles']['category']['description'] : '';
					$taxonomy_name = 'category';
				} elseif(is_tag()){
					$default_desc = isset($settings['titles_tax_titles']['post_tag']['description']) ? $settings['titles_tax_titles']['post_tag']['description'] : '';
					$taxonomy_name = 'post_tag';
				} else{
					$taxonomy_name = $term->taxonomy;
					$default_desc = isset($settings['titles_tax_titles'][$taxonomy_name]['description']) ? $settings['titles_tax_titles'][$taxonomy_name]['description'] : '';
				}

				$disabled = isset($settings['titles_tax_titles'][$taxonomy_name]['disabled']);

				$description = !empty($term_meta_desc) ? $term_meta_desc : $default_desc;

				if(!empty($disabled)){
					$description = self::replace_variables($description);
					echo '<meta name="description" content="' . esc_attr(self::truncate_desc($description)) . '">';
				}
			}
		}
		
		// Author archive
		if(is_author() && !empty($settings['titles_archives_author_desc']) && empty($settings['titles_archives_author_disable'])){
			$description = self::replace_variables($settings['titles_archives_author_desc']);
			echo '<meta name="description" content="'.esc_attr(self::truncate_desc($description)).'" >';
		}
		
		// Date archive
		if(is_date() && !empty($settings['titles_archives_date_desc']) && empty($settings['titles_archives_date_disable'])){
			$description = self::replace_variables($settings['titles_archives_date_desc']);
			echo '<meta name="description" content="'.esc_attr(self::truncate_desc($description)).'" >';
		}
		
		// Search archive
		if(is_search() && !empty($settings['titles_archives_search_desc'])){
			$description = self::replace_variables($settings['titles_archives_search_desc']);
			echo '<meta name="description" content="'.esc_attr(self::truncate_desc($description)).'" >';
		}
		
		// 404 archives
		if(is_404() && !empty($settings['titles_archives_404_desc'])){
			$description = self::replace_variables($settings['titles_archives_404_desc']);
			echo '<meta name="description" content="'.esc_attr(self::truncate_desc($description)).'" >';
		}
	}
	
	static function add_rel_link_pages(){
		global $siteseo, $paged;

		if(empty($siteseo->setting_enabled['toggle-titles'])){
			return;
		}

		if(!empty($siteseo->titles_settings['titles_paged_rel'])){

			if(get_previous_posts_link()){

				echo '<link rel="prev" href="'.esc_url(get_pagenum_link($paged - 1)).'" />';
			}
			if(get_next_posts_link()){

				echo '<link rel="next" href="'.esc_url(get_pagenum_link($paged + 1)).'" />';
			}
		}
	}

	static function date_time_publish(){
		global $siteseo;
		
		if(empty($siteseo->setting_enabled['toggle-titles'])){
			return;
		}
		
		if(!is_singular()){
			return;
		}
		
		
		$current_post_type = get_post_type();
		
		$type_settings = isset($siteseo->titles_settings['titles_single_titles'][$current_post_type]) ? $siteseo->titles_settings['titles_single_titles'][$current_post_type] : '';
		
		// post type
		if(!empty($type_settings['date'])){
			$published_time = get_the_date('c');
			$modified_time = get_the_modified_date('c');
			echo '<meta property="article:published_time" content="'. esc_attr($published_time) .'">';
			echo '<meta property="article:modified_time" content="'. esc_attr($modified_time) .'">';
		}
		
		// thumbnails
		if(!empty($type_settings['thumb_gcs'])){
			if(get_the_post_thumbnail_url(get_the_ID())){
				echo '<meta name="thumbnail" content="'.esc_url(get_the_post_thumbnail_url(get_the_ID())).'">';
			}
		}

	}

	static function truncate_desc($desc){
		return trim($desc);
	}
}
media.php000064400000057557151526435000006360 0ustar00<?php

namespace SoftWP;

// Are we being accessed directly ?
if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Media{
	
	static $compress_content_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
	
	static $edit_content_types = [
							'image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 
							'image/x-ms-bmp', 'image/tiff', 'image/webp', 
							'image/vnd.adobe.photoshop', 'application/pdf', 
							'image/x-portable-pixmap', 'image/x-icon', 'image/vnd-ms.dds'
							];
							
	static $edit_quality_content_types = ['image/jpeg', 'image/png', 'image/webp'];

	static function can_manage_media(){
		
		global $post;
		
		if(!is_admin() || !current_user_can('upload_files') || empty($post) || empty($post->ID) || $post->post_type != 'attachment'){
			define('SOFTACULOUS_PRO_CAN_PHOTOPEA_EDIT', 0);
			define('SOFTACULOUS_PRO_CAN_COMPRESS', 0);
			define('SOFTACULOUS_PRO_CAN_REPLACE_MEDIA', 0);
			return false;
		}
		
		define('SOFTACULOUS_PRO_CAN_REPLACE_MEDIA', 1);
		
		$attachment_path = get_attached_file($post->ID);
		$original_size = filesize($attachment_path);
		$original_size_kb = round($original_size / 1024);
		$attachment_mime_type = mime_content_type($attachment_path);

		// The action buttons
		if(in_array($attachment_mime_type, \SoftWP\Media::$edit_content_types)){
			add_action('admin_enqueue_scripts', '\SoftWP\Media::enqueue_photopea_scripts');
			define('SOFTACULOUS_PRO_CAN_PHOTOPEA_EDIT', 1);
		}else{
			define('SOFTACULOUS_PRO_CAN_PHOTOPEA_EDIT', 0);
		}
		
		if(0 && in_array($attachment_mime_type, \SoftWP\Media::$compress_content_types)){
			add_action('admin_enqueue_scripts', '\SoftWP\Media::enqueue_compress_scripts');
			define('SOFTACULOUS_PRO_CAN_COMPRESS', 1);
		}else{
			define('SOFTACULOUS_PRO_CAN_COMPRESS', 0);
		}
		
		return true;
	}

	static function can_photopea_edit(){
		
		if(!defined('SOFTACULOUS_PRO_CAN_PHOTOPEA_EDIT')){
			\SoftWP\Media::can_manage_media();
		}
		
		return SOFTACULOUS_PRO_CAN_PHOTOPEA_EDIT;
	}

	static function can_compress(){
		
		if(!defined('SOFTACULOUS_PRO_CAN_COMPRESS')){
			\SoftWP\Media::can_manage_media();
		}
		
		return SOFTACULOUS_PRO_CAN_COMPRESS;
	}

	static function can_replace_media(){
		
		if(!defined('SOFTACULOUS_PRO_CAN_REPLACE_MEDIA')){
			\SoftWP\Media::can_manage_media();
		}
		
		return SOFTACULOUS_PRO_CAN_REPLACE_MEDIA;
	}

	// Register the meta box
	static function register_meta_box(){
		
		if(!\SoftWP\Media::can_manage_media()){
			return false;
		}
		
		add_meta_box(
			'softaculous_pro_media_meta_box',
			__('Action Buttons', 'softaculous-pro'),
			'\SoftWP\Media::meta_box_callback',
			'attachment',
			'side',
			'low'
		);
	}

	// Callback function to render the meta box
	static function meta_box_callback($post){
		
		// Nonce field for security
		//wp_nonce_field('softaculous_pro_media_meta_box_nonce', 'custom_nonce');

		// The action buttons
		if(\SoftWP\Media::can_photopea_edit()){
			echo '<button type="button" class="button" id="edit_with_photopea" data-image-url="' . esc_url(wp_get_attachment_url($post->ID)) . '" data-original-image-url="' . esc_url(wp_get_attachment_url($post->ID)) . '" style="margin-right: 5px; margin-top: 10px;">'.__('Edit with Photopea', 'softaculous-pro').'</button>';
		}
		
		if(\SoftWP\Media::can_compress()){
		
			$attachment_path = get_attached_file($post->ID);
			$original_size = filesize($attachment_path);
			$original_size_kb = round($original_size / 1024);
			
			echo '<button type="button" class="button compress-image-button" data-image-id="' . $post->ID . '" data-original-size="' . $original_size_kb . '" data-image-type="' . esc_attr(get_post_mime_type($post)) . '"  style="margin-right: 5px; margin-top: 10px;">'.__('Compress Image', 'softaculous-pro').'</button>';
		}
		
		if(\SoftWP\Media::can_replace_media()){
		
			echo '<a href="' . esc_url(admin_url('upload.php?page=assistant&act=media-replace&id=' . $post->ID)) . '" class="button replace-media-button" style="margin-right: 5px; margin-top: 10px; display: inline-block;">'.__('Replace Media', 'softaculous-pro').'</a>';
			
		}
		
	}

	//////////////////////////////////
	// Edit with Photopea 
	//////////////////////////////////

	// Function to enqueue scripts and styles for the Photopea modal
	static function enqueue_photopea_scripts(){
		
		if(!\SoftWP\Media::can_photopea_edit()){
			return false;
		}
		
		add_action('admin_footer', '\SoftWP\Media::enqueue_photopea_button_script');
		
		wp_enqueue_script('softaculous-pro-photopea-edit', SOFTACULOUS_PRO_PLUGIN_URL . 'assets/js/photopea_edit.js', ['jquery'], SOFTACULOUS_PRO_VERSION, true);

		wp_localize_script('softaculous-pro-photopea-edit', 'spro_photopea', array('ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('softaculous_pro_js_nonce')));
		
	}

	// Enqueue the Photopea modal and button script in WordPress
	static function enqueue_photopea_button_script(){
		
		global $post;
		
		if(!\SoftWP\Media::can_photopea_edit()){
			return false;
		}
		
	?>
	<style>
	#softaculous-pro-photopea-modal {
		display: none;
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background: rgba(0, 0, 0, 0.8);
		z-index: 999999;
		pointer-events: auto; 
	}
	#softaculous-pro-photopea-white-bar {
		position: relative;
		top: 0;
		left: 0;
		width: 100%;
		height: 30px;
		background-color: white;
		z-index: 1000; 
	}
	#softaculous-pro-photopea-iframe {
		width: 100%;
		height: calc(100% - 80px); 
		border: none;
		z-index: 9999; 
		pointer-events: auto; 
	}
	#softaculous-pro-photopea-actions {
		position: absolute;
		bottom: 0;
		left: 0;
		width: 100%;
		height: 50px;
		background: #fff;
		display: flex;
		justify-content: flex-end; 
		align-items: center;
		box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.2);
	}
	#softaculous-pro-photopea-actions .softaculous-pro-quality-section {
		display: flex;
		align-items: center;
		margin-right: auto;
		margin-left: 10px;
	}
	#softaculous-pro-photopea-actions .softaculous-pro-quality-section label {
		margin-right: 5px;
		font-size: 15px;
		font-weight: bold;
		color: black;
		cursor:pointer;
	}
	#softaculous-pro-photopea-actions .softaculous-pro-quality-section input {
		width: 70px;
		padding: 3px;
		text-align: center;
		border: 1px solid #9fa1a6;
		border-radius: 3px;
		color:black;
	}
	#softaculous-pro-photopea-actions button {
		padding: 8px 15px;
		background-color: #0073aa;
		color: white;
		border: none;
		border-radius: 3px;
		cursor: pointer;
		margin-left: 3px; 
	}
	#softaculous-pro-photopea-actions button:hover {
		background-color: #005177;
	}
	</style>

	<div id="softaculous-pro-photopea-modal">
		<div id="softaculous-pro-photopea-white-bar"></div>
		<iframe id="softaculous-pro-photopea-iframe" src=""></iframe>
		<div id="softaculous-pro-photopea-actions">
			<div class="softaculous-pro-quality-section" id="softaculous-pro-quality-input-container" style="display: none;">
				<label for="softaculous-pro-quality-input"><?php _e('Quality', 'softaculous-pro');?>: </label>
				<input type="number" id="softaculous-pro-quality-input" value="100" min="1" max="100" />
			</div>
			<button id="softaculous-pro-save-photopea"><?php _e('Save', 'softaculous-pro');?></button>
			<button id="softaculous-pro-save-close-photopea"><?php _e('Save & Close', 'softaculous-pro');?></button>
			<button id="softaculous-pro-save-as-photopea"><?php _e('Save As', 'softaculous-pro');?></button>
			<button id="softaculous-pro-cancel-photopea"><?php _e('Cancel', 'softaculous-pro');?></button>
		</div>
	</div>
	<?php
	}
	
	static function upload_photopea_image() {
		
		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
			
			$jsonData = file_get_contents('php://input');
			$p = json_decode($jsonData);
			
			if(!is_admin() || !current_user_can('upload_files') || !isset($p->softaculous_pro_security) || !wp_verify_nonce(sanitize_text_field(wp_unslash($p->softaculous_pro_security)), 'softaculous_pro_js_nonce')){
				wp_send_json_error(__('Security Check Failed!', 'softaculous-pro'));
			}

			// Check if a quality parameter is provided, defaulting to 100
			$quality = isset($p->quality) ? intval($p->quality) : 100;
			$quality = max(1, min($quality, 100));

			$base64ImageData = $p->source;
			$save_as_new = (isset($p->save_as_new) ? 1 : 0);
			
			if(empty($save_as_new)){
				$originalImageUrl = $p->original_image_url;
				$attachment_id = attachment_url_to_postid($originalImageUrl);
				if (!$attachment_id) {
					wp_send_json_error(__("Original image attachment not found", 'softaculous-pro'));
					return;
				}

				$filePath = get_attached_file($attachment_id);
				if (!$filePath) {
					wp_send_json_error(__("Original image path not found", 'softaculous-pro'));
					return;
				}
			}else{

				$newImageName = sanitize_file_name($p->new_image_name);  

				$extension = pathinfo($newImageName, PATHINFO_EXTENSION);
				$baseFileName = pathinfo($newImageName, PATHINFO_FILENAME);

				// Sanitize and create a proper path to save the new image in the uploads directory
				$upload_dir = wp_upload_dir();
				$filePath = $upload_dir['path'] . '/' . $newImageName;
				
				$newFileName = basename($filePath);
				
				if(file_exists($filePath)){
					wp_send_json_error(__("File already exists. Please choose another file name", 'softaculous-pro'));
					return;
				}
			}

			// Decode the base64 image data
			$imageData = base64_decode(preg_replace('/^data:image\/(jpeg|png);base64,/', '', $base64ImageData));

			if ($imageData === false) {
				wp_send_json_error(__("Failed to decode base64 image data", 'softaculous-pro'));
				return;
			}
			
			if(empty($quality) || $quality > 99){
				$saved = file_put_contents($filePath, $imageData);
			}else{

				// Create an image resource from the decoded data
				$image = imagecreatefromstring($imageData);
				if ($image === false) {
					wp_send_json_error(__("Failed to create image from data", 'softaculous-pro'));
					return;
				}

				$saved = false;
				if (strpos($filePath, '.jpg') !== false || strpos($filePath, '.jpeg') !== false) {
					
					$saved = imagejpeg($image, $filePath, $quality);

				}elseif (strpos($filePath, '.png') !== false) {
					
					$paletteImage = imagecreatetruecolor(imagesx($image), imagesy($image));
					
					imagesavealpha($paletteImage, true);
					imagealphablending($paletteImage, false);
					$transparency = imagecolorallocatealpha($paletteImage, 0, 0, 0, 127);
					imagecolortransparent($paletteImage, $transparency);
					imagecopyresampled($paletteImage, $image, 0, 0, 0, 0, imagesx($image), imagesy($image), imagesx($image), imagesy($image));

					// Reduce to a set number of colors to save space
					$maxColors = ($quality < 100) ? max((int)($quality / 10), 20) : 256;
					imagetruecolortopalette($paletteImage, true, $maxColors);

					// Set compression level based on quality (0 = no compression, 9 = max compression)
					$compressionLevel = round((100 - $quality) / 100 * 9);
					
					// Don't pass 0 otherwise it will create image larger in size than the original one
					if(empty($compressionLevel)){
						$compressionLevel = 1;
					}
					
					$saved = imagepng($paletteImage, $filePath, $compressionLevel);

				}elseif (strpos($filePath, '.webp') !== false) {
					
					$saved = imagewebp($image, $filePath, $quality);

				}else{
					wp_send_json_error(__("Unsupported image format", 'softaculous-pro'));
					return;
				}

				imagedestroy($image);
			}

			if (!$saved) {
				wp_send_json_error(__("Failed to save the image", 'softaculous-pro'));
				return;
			}
			
			if(!empty($save_as_new)){

				// Attach the new file to the WordPress media library
				$attachment = array(
						'guid'           => $upload_dir['url'] . '/' . basename($filePath),
						'post_mime_type' => mime_content_type($filePath),
						'post_title'     => preg_replace('/\.[^.]+$/', '', basename($filePath)),
						'post_content'   => '',
						'post_status'    => 'inherit'
					);

				$attachment_id = wp_insert_attachment($attachment, $filePath);
				
				if(is_wp_error($attachment_id)) {
					wp_send_json_error(__("Failed to insert the new image as attachment", 'softaculous-pro'));
				}
			}
			
			$metadata = wp_generate_attachment_metadata($attachment_id, $filePath);
			if (is_wp_error($metadata)) {
				wp_send_json_error(__("Failed to regenerate image sub-sizes", 'softaculous-pro'));
			}

			wp_update_attachment_metadata($attachment_id, $metadata);
			$new_image_url = wp_get_attachment_url($attachment_id);

			wp_send_json_success(array(
				'new_image_url' => $new_image_url,
				'message' => __('Image saved successfully', 'softaculous-pro'),
				));
		}
	}

	//////////////////////////////////
	// Compress Image 
	//////////////////////////////////

	static function enqueue_compress_scripts(){
		
		if(!\SoftWP\Media::can_compress()){
			return false;
		}
		
		wp_enqueue_script('softaculous_pro_enqueue_compress_scripts', SOFTACULOUS_PRO_PLUGIN_URL .  '/assets/js/compress_image.js', ['jquery'], SOFTACULOUS_PRO_VERSION, true);
		wp_localize_script('softaculous_pro_enqueue_compress_scripts', 'spro_compress', array(
			'ajax_url' => admin_url('admin-ajax.php'),
			'nonce' => wp_create_nonce('softaculous_pro_js_nonce')
			));
		
	}
	
	static function calculate_compressed_size() {

		if(!is_admin() || !current_user_can('upload_files') || !isset($_POST['softaculous_pro_security']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['softaculous_pro_security'])), 'softaculous_pro_js_nonce')){
			wp_send_json_error(__('Security Check Failed!', 'softaculous-pro'));
		}

		if (isset($_POST['image_id'])) {
			$image_id = intval($_POST['image_id']);
			$image_path = get_attached_file($image_id);

			if ($image_path) {
				$compressed_image_path = \SoftWP\Media::compress_image($image_path, 40, false);
				$compressed_size = round(filesize($compressed_image_path) / 1024);

				wp_send_json_success(array('compressed_size' => $compressed_size));
			}else {
				wp_send_json_error(__('Invalid image path.', 'softaculous-pro'));
			}
		}else {
			wp_send_json_error(__('No image ID provided.', 'softaculous-pro'));
		}
	}

	static function compress_image($image_path, $quality, $save_image = true) {
		$info = getimagesize($image_path);
		$compressed_image_path = '';

		if ($info['mime'] == 'image/jpeg') {
	  $image = imagecreatefromjpeg($image_path);
	  $compressed_image_path = $save_image ? $image_path : str_replace('.jpg', '-temp.jpg', $image_path);
	  imagejpeg($image, $compressed_image_path, $quality);

		}elseif ($info['mime'] == 'image/png') {
				$image = imagecreatefrompng($image_path);
				$compressed_image_path = $save_image ? $image_path : str_replace('.png', '-temp.png', $image_path);

				// Convert to a palette-based image to reduce bit depth
				$paletteImage = imagecreatetruecolor(imagesx($image), imagesy($image));
				imagecopy($paletteImage, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));

				// Reduce to a set number of colors to save space
				$maxColors = ($quality < 100) ? max((int)($quality / 10), 20) : 256;
				imagetruecolortopalette($paletteImage, true, $maxColors);

				// Set compression level based on quality (0 = no compression, 9 = max compression)
				$compressionLevel = ($quality < 100) ? 9 - (int)($quality / 10) : 9;

				imagepng($paletteImage, $compressed_image_path, $compressionLevel);

		}elseif ($info['mime'] == 'image/webp') {
				$image = imagecreatefromwebp($image_path);
				$compressed_image_path = $save_image ? $image_path : str_replace('.webp', '-temp.webp', $image_path);
				imagewebp($image, $compressed_image_path, $quality);
		}else {
				return __('Unsupported image type.', 'softaculous-pro');
		}

		return $compressed_image_path;
	}
	
	static function replace_compressed_image() {

		if(!is_admin() || !current_user_can('upload_files') || !isset($_POST['softaculous_pro_security']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['softaculous_pro_security'])), 'softaculous_pro_js_nonce')){
			wp_send_json_error(__('Security Check Failed!', 'softaculous-pro'));
		}

		if (isset($_POST['image_id'])) {
			$image_id = intval($_POST['image_id']);
			$image_path = get_attached_file($image_id);

			if ($image_path) {
				$compressed_image_path = \SoftWP\Media::compress_image($image_path, 40, true);
				if ($compressed_image_path) {
					require_once(ABSPATH . 'wp-admin/includes/image.php');
					$attach_data = wp_generate_attachment_metadata($image_id, $compressed_image_path);
					wp_update_attachment_metadata($image_id, $attach_data);

					$new_image_url = wp_get_attachment_url($image_id);

					wp_send_json_success(array('message' => __('Image has been successfully compressed and replaced.', 'softaculous-pro'), 'new_image_url' => $new_image_url));
				}else {
					wp_send_json_error(__('Compression and replacement failed.', 'softaculous-pro'));
				}
			}else {
				wp_send_json_error(__('Invalid image path.', 'softaculous-pro'));
			}
		}else {
			wp_send_json_error(__('No image ID provided.', 'softaculous-pro'));
		}
	}

	//////////////////////////////////
	// Replace Media 
	//////////////////////////////////
	
	// Add Replace Media link on Media page in List Mode
	static function add_media_row_action($actions, $post){
		
		if(!\SoftWP\Media::can_replace_media()){
			return $actions;
		}
		
		$url = admin_url('upload.php');
		
		$url = add_query_arg(array(
			'page' => 'assistant',
			'act' => 'media-replace',
			'id' => $post->ID,
		), $url);
		
		$actions['softaculous_pro_replace_media'] = '<a href="'.esc_url($url).'" rel="permalink">'.esc_html__('Replace Media', 'softaculous_pro').'</a>';
		
		// Remove it from Pagelayer as we are adding our own
		if(isset($actions['pagelayer_replace_media'])){
			unset($actions['pagelayer_replace_media']);
		}
		
		return $actions;
		
	}

	//function is called first to select the route 
	static function replace_media_page(){
		
		global $pl_error;

		if(!current_user_can('upload_files')){
			wp_die(esc_html__('You do not have permission to upload files.', 'softaculous-pro'));
		}
		
		$post_id = (int) $_GET['id'];
		
		if(empty($post_id)){
			wp_die(esc_html__('Invalid Media ID', 'softaculous-pro'));
		}
		
		// Load the attachment
		$post = get_post($post_id);
		
		if(empty($post) || is_wp_error($post)){
			wp_die(esc_html__('Media not found', 'softaculous-pro'));
		}
		
		// Process the POST !
		if(isset($_FILES['userfile'])){
		
			if(!check_admin_referer('softaculous-pro-media')){
				wp_die('Invalid Nonce');
			}
			
			/** Check if file is uploaded properly **/
			if(!is_uploaded_file($_FILES['userfile']['tmp_name'])){
				$pl_error['upload_error'] = __('No file was uploaded ! Please try again.', 'softaculous-pro');
				\SoftWP\Media::replace_media_theme();
				return;
			}
			
			if(isset($_FILES['userfile']['error']) && $_FILES['userfile']['error'] > 0){
				$pl_error['upload_error'] = __('There was some error uploading the file ! Please try again.', 'softaculous-pro');
				\SoftWP\Media::replace_media_theme();
				return;
			}
			
			$filedata = wp_check_filetype_and_ext($_FILES['userfile']['tmp_name'], $_FILES['userfile']['name']);
			
			if ($filedata['ext'] == false){
				$pl_error['ext_error'] = __('The File type could not be determined. Please upload a permitted file type.', 'softaculous-pro');
				\SoftWP\Media::replace_media_theme();
				return;
			}
			
			$result = \SoftWP\Media::replace_attachment($_FILES['userfile']['tmp_name'], $post_id, $err);
			
			if(empty($result)){
				$pl_error['replace_error'] = $err;
				\SoftWP\Media::replace_media_theme();
				return;
			}
			
			$redirect_success = admin_url('post.php');
			$redirect_success = add_query_arg(array(
				'action' => 'edit', 
				'post' => $post_id,
			), $redirect_success);
			
			echo '<meta http-equiv="refresh" content="0;url='.$redirect_success.'" />';
		
		}
		
		// Show the theme
		\SoftWP\Media::replace_media_theme();
		
	}

	// Report an error
	static function report_error($error = array()){

		if(empty($error)){
			return true;
		}

		$error_string = '<b>'.__('Please fix the below errors', 'softaculous-pro').' :</b> <br />';

		foreach($error as $ek => $ev){
			$error_string .= '* '.$ev.'<br />';
		}

		echo '<div id="message" class="error"><p>'
						. __($error_string, 'softaculous-pro')
						. '</p></div>';
	}


	// Theme of the page
	static function replace_media_theme(){
		
		global $pl_error;
		
		\SoftWP\Media::report_error($pl_error);echo '<br />';
		
		$id = (int) $_GET['id'];
		
	?>
	<div class="wrap">
	<h1><?php echo esc_html__("Replace Media File", 'softaculous-pro'); ?></h1>
	<form enctype="multipart/form-data" method="POST">
		<div class="editor-wrapper">
			<section class="image_chooser wrapper">
				<input type="hidden" name="ID" id="ID" value="<?php echo $id ?>" />
				<p><?php echo esc_html__("Choose a file to upload from your computer", 'softaculous-pro'); ?></p>
				<div class="drop-wrapper">
					<p><input type="file" name="userfile" id="userfile" /></p>
					<?php wp_nonce_field('softaculous-pro-media'); ?>
				</div>
			</section>
			<section class="form_controls wrapper">
				<input id="submit" type="submit" class="button button-primary" name="submit" value="<?php echo esc_attr__("Upload", 'softaculous-pro');?>" />
			</section>
		</div>
	</form>
	<?php

	}

	// Replace the uploaded media with the new one
	static function replace_attachment($file, $post_id, &$error = ''){

		if(!current_user_can('upload_files')){
			wp_die(esc_html__('You do not have permission to upload files.', 'softaculous-pro'));
		}

		if(function_exists('wp_get_original_image_path')){
			$targetFile = wp_get_original_image_path($post_id);
		}else{
			$targetFile = trim(get_attached_file($post_id));
		}
		
		$fileparts = pathinfo($targetFile);
		$filePath = isset($fileparts['dirname']) ? trailingslashit($fileparts['dirname']) : '';
		$fileName = isset($fileparts['basename']) ? $fileparts['basename'] : '';
		$filedata = wp_check_filetype_and_ext($targetFile, $fileName);
		$fileMime = (isset($filedata['type'])) ? $filedata['type'] : false;
		$permissions = fileperms($targetFile) & 0644;
		
		if(empty($targetFile)){
			$error = __('Failed to determine the media file path !', 'softaculous-pro');
			return false;
		}
		
		if(empty($filePath)){
			$error = __('No folder for the target found !', 'softaculous-pro');
			return false;
		}
		
		// Remove the files of the original attachment
		\SoftWP\Media::remove_attachment_files($post_id);
		
		$result_moved = move_uploaded_file($file, $targetFile);
		
		if (false === $result_moved){
			$error = sprintf( esc_html__('The uploaded file could not be moved to %1$s. This is most likely an issue with permissions, or upload failed.', 'softaculous-pro'), $targetFile );
			return false;
		}
		
		if ($permissions > 0){
			chmod( $targetFile, $permissions ); // restore permissions
		}
		
		$updated = update_attached_file($post_id, $targetFile);
		
		$target_url = wp_get_attachment_url($post_id);
		
		// Run the filter, so other plugins can hook if needed.
		$filtered = apply_filters( 'wp_handle_upload', array(
			'file' => $targetFile,
			'url'  => $target_url,
			'type' => $fileMime,
		), 'sideload');
		
		// Check if file changed during filter. Set changed to attached file meta properly.
		if (isset($filtered['file']) && $filtered['file'] != $targetFile ){
			update_attached_file($post_id, $filtered['file']);
		}

		$metadata = wp_generate_attachment_metadata($post_id, $targetFile);
		wp_update_attachment_metadata($post_id, $metadata);

		return true;
		
	}

	static function remove_attachment_files($post_id){

		if(!current_user_can('upload_files')){
			wp_die(esc_html__('You do not have permission to upload files.', 'softaculous-pro'));
		}
		
		$meta = wp_get_attachment_metadata( $post_id );

		if (function_exists('wp_get_original_image_path')){ // WP 5.3+
			$fullFilePath = wp_get_original_image_path($post_id);
		}else{
			$fullFilePath = trim(get_attached_file($post_id));
		}

		$backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
		
		$file = $fullFilePath;
		
		$result = wp_delete_attachment_files($post_id, $meta, $backup_sizes, $file);

		// If attached file is not the same path as file, this indicates a -scaled images is in play.
		$attached_file = get_attached_file($post_id);
		
		if ($file !== $attached_file && file_exists($attached_file)){
			@unlink($attached_file);
		}
	}
	
}
setup.php000064400000023414151526435000006422 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

$steps = array(
	'welcome' => __('Welcome', 'softaculous-pro'),
	'type' => __('Business Type','softaculous-pro'),
	'title' => __('Site Title','softaculous-pro'),
	'features' => __('Goals','softaculous-pro'),
	'import_theme' => __('Choose Template','softaculous-pro'),
);

$active_step = isset($_GET['step']) && array_key_exists($_GET['step'], $steps) ? $_GET['step'] : 'welcome';

include_once(dirname(__FILE__).'/onboarding.php');
$softaculous_pro['templates'] = softaculous_pro_get_templates_list();
$spro_setup_info = get_option('softaculous_pro_setup_info');
$spro_onboarding_done = get_option('softaculous_pro_onboarding_done');

update_option('softaculous_pro_onboarding_shown', time());

require_once ABSPATH . 'wp-admin/includes/plugin.php';
$installed_plugins = get_plugins();

if(!empty($softaculous_pro['branding']['default_hf_bg'])){
	echo '
	<style>
	.softaculous-pro-wizard-sidebar {
		background-color:'.$softaculous_pro['branding']['default_hf_bg'].' !important;
	}
	</style>';
}

if(!empty($softaculous_pro['branding']['default_hf_text'])){
	echo '
	<style>
	.softaculous-pro-wizard-steps li, .softaculous-pro-wizard-steps li::before {
		color:'.$softaculous_pro['branding']['default_hf_text'].' !important;
		border-color:'.$softaculous_pro['branding']['default_hf_text'].' !important;
	}
	.softaculous_pro_return_btn span, .dashicons-exit::before {
		color:'.$softaculous_pro['branding']['default_hf_text'].' !important;
	}
	</style>';
}

?>
<style>
*,
*::before,
*::after {
	box-sizing: content-box;
}
</style>

<div class="softaculous-pro-wizard">
	<div class="softaculous-pro-wizard-sidebar">
		<div class="softaculous-pro-setup-logo">
			<a href="<?php echo admin_url('admin.php?page=assistant&act=onboarding'); ?>">
				<img src="<?php echo esc_attr($softaculous_pro['branding']['logo_url']);?>" style="max-width:200px;" />
			</a>
		</div>
		<div class="softaculous-pro-steps-holder">
			<ol class="softaculous-pro-wizard-steps">
				<?php foreach ($steps as $key => $name) : ?>
                <a href="admin.php?page=assistant&act=onboarding&step=<?php echo $key; ?>"><li class="<?php echo ($key == $active_step ? 'active_step' : ''); ?>"><span
                        data-step="<?php echo $key; ?>"><?php echo $name; ?></span></li>
				</a>
				<?php endforeach; ?>
			</ol>
		</div>
		<a class="softaculous_pro_return_btn" style="cursor:pointer;" onclick="return softaculous_pro_onboarding_dismiss(event);">
		<span class="dashicons dashicons-exit"></span><span><?php _e('Exit', 'softaculous-pro'); ?></span></a>
	</div>
	
	<div class="softaculous-pro-wizard-content" data-active-panel="<?php echo $active_step; ?>">
		<!-- Step Welcome -->
		<div class="softaculous-pro-wizard-inner" data-panel="welcome">
			<div class="softaculous-pro-wizard-inner-content">
				<h1><?php _e('Welcome to the Onboarding process!', 'softaculous-pro'); ?></h1>
				<p><?php _e('This process will help you choose a professional template for your website and install plugins that you might need to achieve your goal for creating this website', 'softaculous-pro'); ?>
				</p>
				<?php if (!empty($spro_onboarding_done)): ?>
				<div class="softaculous-pro-wizard-buttons">
					<input type="checkbox" id="onboarding_done_confirm" name="onboarding_done_confirm" style="margin:0px;" /> &nbsp;&nbsp;
					<label for="onboarding_done_confirm" style="cursor:pointer;"><?php _e('It looks like you have already completed the onboarding process. You might lose data if you run the onboarding process again. Select this checkbox to confirm that you agree.', 'softaculous-pro'); ?></label>
				</div>
				<?php endif; ?>
				<div class="softaculous-pro-wizard-buttons">
                    <button class="step_btn step_next_btn" data-step="type"
                        onclick="softaculous_pro_next_handler(this)"><?php _e('Get Started', 'softaculous-pro'); ?><span
                            class="dashicons dashicons-arrow-right-alt"></span></button>
		
                    <button class="step_btn step_next_btn step_dismiss_btn" data-step="type"
                        onclick="softaculous_pro_onboarding_dismiss(event);"><?php _e('No, I don\'t want to try an easy setup process', 'softaculous-pro'); ?><span
                            class="dashicons dashicons-no-alt"></span></button>
				</div>
			</div>
		</div>
		<!-- Step Type -->
		<div class="softaculous-pro-wizard-inner" data-panel="type">
			<div class="softaculous-pro-wizard-inner-content">
				<h1><?php _e('How would you categorize your website ?', 'softaculous-pro'); ?></h1>
				<p><?php _e('This helps us recommend design and functionalities for your website', 'softaculous-pro'); ?></p>
			</div>
			<div class="softaculous-pro-category-input">
                <input type="text" class="softaculous_pro_input" id="cat_input" placeholder="<?php _e('Search for a category', 'softaculous-pro'); ?>" />
			</div>
			<div class="softaculous-pro-category-holder">
				<div class="softaculous-pro-categories-list">
					<?php foreach ($softaculous_pro['templates']['categories'] as $cslug => $cdata) : ?>
                    <div class="category_btn">
						<input type="button" id="cat_button_<?php echo $cslug; ?>" value= <?php echo esc_html($cdata['en']); ?> data-target=<?php echo $cslug; ?> />
					</div>
					<?php endforeach; ?>
                    <div id="spro_no_cat_results" style="display:none;">
						<h3><i><?php echo __('No results match your search criteria', 'softaculous-pro'); ?></i></h3>
					</div>
				</div>
			</div>
			<br /><br />
			<div class="softaculous-pro-wizard-buttons">
                <button onclick="softaculous_pro_prev_handler(this)" data-step="welcome"
                    class="step_btn step_prev_btn"><?php _e('Previous Step', 'softaculous-pro'); ?></button>
                <button class="step_btn step_next_btn" data-step="title"
                    onclick="softaculous_pro_next_handler(this)"><?php _e('Continue', 'softaculous-pro'); ?> <span
                        class="dashicons dashicons-arrow-right-alt"></span></button>
            </div>
		</div>
		<!-- Step Title -->
		<div class="softaculous-pro-wizard-inner" data-panel="title">
			<div class="softaculous-pro-wizard-inner-content">
				<h1><?php _e('Enter the title of your new site', 'softaculous-pro'); ?></h1>
				<p><?php _e('Can be changed later', 'softaculous-pro'); ?></p>
			</div>
			<div class="softaculous-pro-title-input">
				<input type="text" class="softaculous_pro_input" placeholder="<?php _e('Enter a title for your website', 'softaculous-pro'); ?>" value="<?php echo esc_html(get_bloginfo('name')); ?>" autocomplete="off"/>
			</div>
            <div class="softaculous-pro-wizard-buttons">
                <button onclick="softaculous_pro_prev_handler(this)" data-step="type"
                    class="step_btn step_prev_btn"><?php _e('Previous Step', 'softaculous-pro'); ?></button>
                <button class="step_btn step_next_btn" data-step="features"
                    onclick="softaculous_pro_next_handler(this)"><?php _e('Continue', 'softaculous-pro'); ?><span
                        class="dashicons dashicons-arrow-right-alt"></span></button>
            </div>
		</div>
		<!-- Step Features -->
		<div class="softaculous-pro-wizard-inner" data-panel="features">
			<div class="softaculous-pro-wizard-inner-content">
				<h1><?php _e('What are you looking to achieve with your new site ?', 'softaculous-pro'); ?></h1>
				<p><?php _e('We will install the appropriate plugins that will add the required functionality to your website', 'softaculous-pro'); ?></p>
			</div>
            <div class="softaculous-pro-features-container">
                <?php foreach(spro_get_features_list() as $slug => $feature):?>
                <label for="<?php echo $slug;?>_input" style="cursor:pointer;">
		<div class="softaculous-pro-features" data-slug="<?php echo $slug; ?>">
                    <div class="softaculous-pro-features-icon">
                        <span class="<?php echo $feature['icon']; ?>"></span>
                    </div>
                    <div class="softaculous-pro-features-text">
                        <h3><?php echo $feature['name']; ?></h3>
                        <p><?php echo $feature['info']; ?></p>
                    </div>
                    <div class="softaculous-pro-features-input">
                        <input type="checkbox" onclick="softaculous_pro_selected_features(this)" id="<?php echo $slug;?>_input" <?php echo (!empty($spro_setup_info) && !empty($spro_setup_info['features']) && in_array($slug, $spro_setup_info['features']) ? 'checked="checked"' : '') ;
						
				foreach($feature['plugin'] as $info){
					if (!empty($info['requires_php']) && version_compare(PHP_VERSION, $info['requires_php'], '<')) {
						echo ' disabled';
						echo ' spro-erro="'.sprintf(__('Requires PHP version %1$s or higher', 'softaculous-pro'), $info['requires_php']).'"';
						break;
					}
					echo (!empty($installed_plugins[$info['plugin_init']]) ? 'checked="checked"' : '');
				} ?>/>
                    </div>
                </div>
	    	</label>
                <?php endforeach; ?>
            </div>
            <div class="softaculous-pro-wizard-buttons">
                <button onclick="softaculous_pro_prev_handler(this)" data-step="title"
                    class="step_btn step_prev_btn"><?php _e('Previous Step', 'softaculous-pro'); ?> </button>
                <button class="step_btn step_next_btn" data-step="import_theme"
                    onclick="softaculous_pro_next_handler(this)"><?php _e('Continue', 'softaculous-pro'); ?> <span
                        class="dashicons dashicons-arrow-right-alt"></span></button>
            </div>
        </div>
        <!-- Step Import theme -->
        <div class="softaculous-pro-wizard-inner" data-panel="import_theme">
            <?php
				softaculous_pro_templates();
			?>
        </div>
	</div>
</div>
license.php000064400000010167151526435000006705 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

include_once SPEEDYCACHE_DIR . '/main/settings.php';

function speedycache_license_page(){
	global $speedycache;
	
	if(isset($_REQUEST['save_speedycache_license'])){
		speedycache_license();
	}
	
	speedycache_add_javascript();
	settings_errors('speedycache-notice');
	
	?>
	
	<div class="speedycache-setting-content">
		<div class="speedycache-tab-group" style="width:78%">
			<table class="wp-list-table fixed striped users speedycache-license-table" cellspacing="1" border="0" width="78%" cellpadding="10" align="center">
				<tbody>
					<tr>				
						<th align="left" width="25%"><?php esc_html_e('SpeedyCache Version', 'speedycache'); ?></th>
						<td><?php
							echo SPEEDYCACHE_PRO_VERSION.(defined('SPEEDYCACHE_PRO') ? ' (Pro Version)' : '');
						?>
						</td>
					</tr>
					<tr>			
						<th align="left" valign="top"><?php esc_html_e('SpeedyCache License', 'speedycache'); ?></th>
						<td align="left">
							<form method="post" action="">
								<span style="color:var(--speedycache-red)">
									<?php echo (defined('SPEEDYCACHE_PRO') && empty($speedycache->license) ? '<span style="color:var(--speedycache-red)">Unlicensed</span> &nbsp; &nbsp;' : '')?>
								</span>
								<input type="hidden" name="speedycache_license_nonce" value="<?php echo wp_create_nonce('speedycache_license');?>"/>
								<input type="text" name="speedycache_license" value="<?php echo (empty($speedycache->license) ? empty($_POST['speedycache_license']) ? '' : speedycache_optpost('speedycache_license') : $speedycache->license['license'])?>" size="30" placeholder="e.g. SPDFY-11111-22222-33333-44444" style="width:300px;"> &nbsp; 
								<input name="save_speedycache_license" class="speedycache-btn speedycache-btn-primary" value="Update License" type="submit">
							</form>
							<?php if(!empty($speedycache->license)){
								
								$expires = $speedycache->license['expires'];
								$expires = substr($expires, 0, 4).'/'.substr($expires, 4, 2).'/'.substr($expires, 6);
								
								echo '<div style="margin-top:10px;">License Status : '.(empty($speedycache->license['status_txt']) ? 'N.A.' : wp_kses_post($speedycache->license['status_txt'])).' &nbsp; &nbsp; &nbsp; 
								'.($speedycache->license['expires'] <= date('Ymd') ? 'License Expires : <span style="color:var(--speedycache-red)">'.esc_attr($expires).'</span>' : (empty($speedycache->license['has_plid']) ? 'License Expires : ' . esc_html($expires) : '')).'
								</div>';
								
							}?>
						</td>
					</tr>
					<tr>
						<th align="left">URL</th>
						<td><?php echo get_site_url(); ?></td>
					</tr>
					<tr>				
						<th align="left">Path</th>
						<td><?php echo ABSPATH; ?></td>
					</tr>
					<tr>				
						<th align="left">Server's IP Address</th>
						<td><?php echo esc_html($_SERVER['SERVER_ADDR']); ?></td>
					</tr>
					<tr>				
						<th align="left">.htaccess is writable</th>
						<td><?php echo (is_writable(ABSPATH.'/.htaccess') ? '<span style="color:var(--speedycache-red)">Yes</span>' : '<span style="color:green">No</span>');?></td>
					</tr>		
				</tbody>
			</table>
		</div>
	<?php speedycache_promotion_tmpl(); ?>
	</div>
<?php
	speedycache_page_footer(true);
}

function speedycache_license(){
	global $speedycache, $lic_resp;

	if(!wp_verify_nonce($_POST['speedycache_license_nonce'], 'speedycache_license')){
		speedycache_notify(array(__('Security Check Failed', 'speedycache'),'error'));
		return;
	}

	$license = sanitize_key($_POST['speedycache_license']);
	
	if(empty($license)){
		speedycache_notify(array(__('The license key was not submitted', 'speedycache'),'error'));
		return;
	}
	
	speedycache_pro_load_license($license);
	
	if(!is_array($lic_resp)){
		speedycache_notify(array(__('The response was malformed<br>'.var_export($lic_resp, true), 'speedycache'), 'error'));
		return;
	}

	$json = json_decode($lic_resp['body'], true);
	
	// Save the License
	if(empty($json['license'])){
		speedycache_notify(array(__('The license key is invalid', 'speedycache'), 'error'));
		return;
		
	}
	
}
functions.php000064400000065434151526435000007302 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

$softaculous_pro_settings = get_option('softaculous_pro_settings', array());

if(!empty($softaculous_pro_settings['disable_comments'])){
	include_once SOFTACULOUS_PRO_PLUGIN_PATH . '/main/disable-comments.php';
}

if(is_admin() && empty($softaculous_pro_settings['disable_ai'])){
	add_action('enqueue_block_editor_assets', '\SoftWP\AI::enqueue_scripts');

	// AJAX ACTIONS
	add_action('wp_ajax_softaculous_ai_generation', '\SoftWP\AI::generate');
	add_action('wp_ajax_softaculous_ai_history', '\SoftWP\AI::load_history');
}

$spro_page = softaculous_pro_optGET('page');
if(is_admin() && !empty($spro_page) && $spro_page == 'assistant'){
	$spro_act = softaculous_pro_optGET('act');
	if(!empty($spro_act) && $spro_act == 'onboarding'){
		include_once(SOFTACULOUS_PRO_PLUGIN_PATH . '/main/onboarding.php');
	}
}

function softaculous_pro_activation_hook(){
	softaculous_pro_update_check();
}

function softaculous_pro_deactivation_hook() {
	
}

function softaculous_pro_uninstall_hook() {
	delete_option('softaculous_pro_version');
	delete_option('softaculous_pro_settings');
	delete_option('softaculous_pro_onboarding_notice_dismiss');
	delete_option('softaculous_pro_ai_notice_dismiss');
	delete_option('softaculous_pro_onboarding_done');
	delete_option('softaculous_pro_onboarding_dismiss');
	delete_option('softaculous_pro_setup_info');
	delete_option('softaculous_pro_onboarding_shown');
	
	wp_clear_scheduled_hook('softaculous_pro_ai_history_cron');
}

function softaculous_pro_load_plugin(){
	
	global $softaculous_pro, $softaculous_pro_settings, $spro_tours;
	
	
	add_action('softaculous_pro_ai_history_cron', '\SoftWP\AI::delete_history'); // Cron for AI History deletion
	if(!is_admin()){
		return false;
	}
	
	// Do we have to redirect the user to onboarding ? 
	if(is_admin() && current_user_can('administrator') && !wp_doing_ajax() && (empty($_GET['act']) || ($_GET['act'] != 'onboarding' && $_GET['act'] != 'license'))){
		
		$spro_is_dismissed = get_option('softaculous_pro_onboarding_dismiss');
		$spro_is_done = get_option('softaculous_pro_onboarding_done');
		$spro_is_shown = get_option('softaculous_pro_onboarding_shown');
		
		if(empty($spro_is_dismissed) && empty($spro_is_done) && empty($spro_is_shown)){
			wp_safe_redirect(admin_url('admin.php?page=assistant&act=onboarding'));
			exit(0);
		}
	}

	softaculous_pro_load_license();
	
	softaculous_pro_rebranding();
	
	// Show key details in Plugins data
	add_filter('plugin_row_meta', 'softaculous_pro_add_plugin_row_links', 10, 2);
	
	// Check for updates
	include_once(SOFTACULOUS_PRO_PLUGIN_PATH.'/lib/plugin-update-checker.php');
	$softaculous_pro_updater = SoftaculousPro_PucFactory::buildUpdateChecker(softaculous_pro_api_url().'updates.php?version='.SOFTACULOUS_PRO_VERSION.'&url='.rawurlencode(site_url()), SOFTACULOUS_PRO_FILE);
	
	// Add the license key to query arguments
	$softaculous_pro_updater->addQueryArgFilter('softaculous_pro_updater_filter_args');
	
	// Show the text to install the license key
	add_filter('puc_manual_final_check_link-softaculous-pro', 'softaculous_pro_updater_check_link', 10, 1);
	
	softaculous_pro_update_check();
	
	// Register AI Post type
	add_action('init', 'softaculous_pro_register_post_type');
	
	$spro_tours = array('assistant' => 'admin.php?page=assistant', 'sidebar' => 'admin.php?page=assistant', 'dashboard' => 'index.php', 'plugins' => 'plugins.php', 'themes' => 'themes.php', 'users' => 'users.php', 'pages' => 'edit.php?post_type=page', 'posts' => 'edit.php');
	
	// Enqueues scripts and styles
	if(softaculous_pro_can_enqueue_assets()){
		add_action('admin_init', 'softaculous_pro_admin');
		add_action('admin_enqueue_scripts', 'softaculous_pro_enqueue_scripts');
	}
	
	if(is_admin() && !empty($_GET['page']) && $_GET['page'] == 'assistant'){
		add_filter('screen_options_show_screen', '__return_false');
	}
	
	add_action('admin_notices', 'softaculous_pro_license_notice');
	
	// Are you the Admin ?
	if(current_user_can('administrator')){
	
		if(softaculous_pro_is_display_notice()){
			add_action('admin_notices', 'softaculous_pro_admin_notice');
		}
		
		add_action('wp_ajax_softaculous_pro_dismissnotice', 'softaculous_pro_dismiss_notice');
		
		// This adds the left menu in WordPress Admin page
		add_action('admin_menu', 'softaculous_pro_admin_menu', 5);
	
		include_once SOFTACULOUS_PRO_PLUGIN_PATH . '/main/admin.php';
		add_action('admin_print_footer_scripts', 'softaculous_pro_assistant', 5);
		
		add_action('wp_ajax_softaculous_pro_wp_ajax', 'softaculous_pro_wp_ajax');
		
		add_action('admin_menu', 'softaculous_pro_remove_admin_elements');

		// Template Installation related ajax calls
		add_action('wp_ajax_softaculous_pro_template_info', 'softaculous_pro_templates_ajax');
		add_action('wp_ajax_softaculous_pro_start_install_template', 'softaculous_pro_templates_ajax');
		add_action('wp_ajax_softaculous_pro_selected_plugin_install', 'softaculous_pro_templates_ajax');
		add_action('wp_ajax_softaculous_pro_download_template', 'softaculous_pro_templates_ajax');
		add_action('wp_ajax_softaculous_pro_import_template', 'softaculous_pro_templates_ajax');
		
		// Setup information
		add_action('wp_ajax_softaculous_pro_setup_info', 'softaculous_pro_templates_ajax');
		
		// dismiss
		add_action('wp_ajax_softaculous_pro_onboarding_dismiss', 'softaculous_pro_templates_ajax');
		
		add_action('wp_ajax_softaculous_pro_option_value', 'softaculous_pro_templates_ajax');
		
	}
	
	// Manage Media hooks
	if(is_admin() && empty($softaculous_pro_settings['disable_manage_media']) && current_user_can('upload_files') /* && !empty($post) && !empty($post->post_type) && $post->post_type == 'attachment' */){
		
		add_action('add_meta_boxes_attachment', '\SoftWP\Media::register_meta_box');
		add_filter('media_row_actions', '\SoftWP\Media::add_media_row_action', 11, 2);
		
		// ajax calls
		add_action('wp_ajax_softaculous_pro_upload_photopea_image', '\SoftWP\Media::upload_photopea_image');
		add_action('wp_ajax_softaculous_pro_calculate_compressed_size', '\SoftWP\Media::calculate_compressed_size');
		add_action('wp_ajax_softaculous_pro_replace_compressed_image', '\SoftWP\Media::replace_compressed_image');
	}
}

function softaculous_pro_templates_ajax() {
	
	if(!current_user_can('administrator')){
		return false;
	}

	include_once(dirname(__FILE__).'/onboarding.php');
	
	if($_REQUEST['action'] == 'softaculous_pro_template_info'){
		softaculous_pro_ajax_template_info();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_selected_plugin_install'){
		softaculous_pro_ajax_selected_plugin();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_start_install_template'){
		softaculous_pro_ajax_start_install_template();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_download_template'){
		softaculous_pro_ajax_download_template();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_import_template'){
		softaculous_pro_ajax_import_template();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_setup_info'){
		softaculous_pro_save_setup_info();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_option_value'){
		softaculous_pro_get_options();
	}
	
	if($_REQUEST['action'] == 'softaculous_pro_onboarding_dismiss'){
		softaculous_pro_onboarding_dismiss();
	}

}

function softaculous_pro_remove_admin_elements(){
	
	if(!empty($_GET['page']) && $_GET['page'] === 'assistant'){
		remove_all_actions('admin_notices');
		remove_all_actions('all_admin_notices');
	}
}

// Update check
function softaculous_pro_update_check(){
	global $softaculous_pro_settings;

	$current_version = get_option('softaculous_pro_version', 0);
	$version = (int) str_replace('.', '', $current_version);

	if($current_version == SOFTACULOUS_PRO_VERSION){
		return true;
	}
	
	// AI is enabled by default so the cron to delete AI history should be added at activation.
	wp_schedule_event(time(), 'daily', 'softaculous_pro_ai_history_cron');
	
	if(empty($softaculous_pro_settings) || !isset($softaculous_pro_settings['ai_history_duration'])){
		$softaculous_pro_settings['ai_history_duration'] = 90; // Setting default AI history duration.
		update_option('softaculous_pro_settings', $softaculous_pro_settings);
	}

	// Save the new Version
	update_option('softaculous_pro_version', SOFTACULOUS_PRO_VERSION);
}

function softaculous_pro_admin(){
	
	global $spro_tours;
	
	include_once SOFTACULOUS_PRO_PLUGIN_PATH . '/main/admin.php';
	
}

// Shows the admin menu of Softaculous
function softaculous_pro_admin_menu() {
	
	$capability = 'activate_plugins';// TODO : Capability for accessing this page

	// Add the menu page
	add_menu_page(__('Assistant'), __('Assistant', 'softaculous-pro'), $capability, 'assistant', 'softaculous_pro_page_handler', 'dashicons-businessperson', 1);
	
}

// The Softaculous Settings Page
function softaculous_pro_page_handler(){
	
	global $softaculous_pro;

	if(!current_user_can('manage_options')){
		wp_die(__('Sorry, but you do not have permissions to change settings.', 'softaculous-pro'));
	}
	
	$act = softaculous_pro_optGET('act');
	
	switch($act){
		
		case 'onboarding':
		include_once(SOFTACULOUS_PRO_PLUGIN_PATH . '/main/setup.php');
		break;
		
		case 'license':
		include_once(SOFTACULOUS_PRO_PLUGIN_PATH . '/main/license.php');
		softaculous_pro_license();
		break;
		
		case 'manage-plugins':
		include_once(SOFTACULOUS_PRO_PLUGIN_PATH . '/main/manage-plugins.php');
		softaculous_pro_manage_plugins();
		break;
		
		case 'media-replace':
		\SoftWP\Media::replace_media_page();
		break;
		
		default:
		include_once(dirname(__FILE__).'/admin.php');
		softaculous_pro_page_settings();
	}

}

function softaculous_pro_can_enqueue_assets(){
	
	global $spro_tours;
	
	if(!is_admin()){
		return false;
	}
	
	$current_page = basename($_SERVER['REQUEST_URI'], PHP_URL_PATH);
	
	if(!empty($_COOKIE['spro-load-tour']) && (!empty($spro_tours)) && array_key_exists($_COOKIE['spro-load-tour'], $spro_tours) && $current_page == $spro_tours[$_COOKIE['spro-load-tour']]){
		return $_COOKIE['spro-load-tour'];
	}
	
	$is_admin_page = basename(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
	if(!empty($_GET['page']) && $_GET['page'] == 'assistant' && $is_admin_page == 'admin.php'){
		return true;
	}
	
	return false;
	
}

function softaculous_pro_enqueue_scripts(){
	
	wp_enqueue_style('softaculous-pro-style-admin', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/css/admin.css', [], SOFTACULOUS_PRO_VERSION);

	wp_enqueue_style('softaculous-pro-style-intro', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/css/intro.css', [], SOFTACULOUS_PRO_VERSION);
	
	wp_enqueue_style( 'softaculous-pro-style-font-awesome', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/font-awesome/css/all.min.css', [], SOFTACULOUS_PRO_VERSION, 'all' );

	wp_enqueue_script('softaculous-pro-script-admin', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/js/admin.js', [], SOFTACULOUS_PRO_VERSION, true);

	wp_enqueue_script('softaculous-pro-script-intro', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/js/intro.js', [], SOFTACULOUS_PRO_VERSION, false);
	
	wp_localize_script('softaculous-pro-script-admin', 'soft_pro_obj', array(
		'admin_url' => esc_url(admin_url()),
		'site_url' => esc_url(site_url()),
		'nonce' => wp_create_nonce('softaculous_pro_js_nonce'),
		'ajax_url' => admin_url('admin-ajax.php')
	));
}

/**
 * Display Softaculous notice on the basis of last dismiss date. When user manually dismisses the notice, it remains for 1 month
 *
 * @since		1.0
 */
function softaculous_pro_is_display_notice(){
	
	$soft_dismissable_notice_date = get_option('softaculous_pro_dismiss_notice_date');
	
	if(empty($soft_dismissable_notice_date)){
		return true;
	}
	
	$soft_dismissable_notice_date2 = new DateTime($soft_dismissable_notice_date);
	$current_date = new DateTime(date('Y-m-d'));
	$date_diff_month = $soft_dismissable_notice_date2->diff($current_date);

	//Do not display notice again for a month
	if($date_diff_month->m < 1){
		return false;
	}
	
	return true;
}

/**
 * Display Softaculous notice in dashboard
 *
 * @since		1.0
 */
function softaculous_pro_admin_notice($force = 0){
	
	if(!empty($_GET['page']) && $_GET['page'] == 'softaculous' && empty($force)){
		return '';
	}
	
	return '';
}

function softaculous_pro_license_notice(){
	
	global $softaculous_pro;
	
	if(is_admin() && current_user_can('activate_plugins') && !wp_doing_ajax()){
		
		$spro_add_nonce_vars = 0;
		
		if(empty($softaculous_pro['license']['license'])){
			$msg = sprintf(__('Your SoftWP plugin is %1$sUnlicensed%2$s. Please enter the license key %3$s here%4$s.', 'softaculous-pro'), 
						'<font style="color:red;"><b>',
						'</b></font>',
						'<a href="'.admin_url('admin.php?page=assistant&act=license').'">',
						'</a>'
						);
		}else{
			
			if(!empty($softaculous_pro['license']['url_mismatch'])){
				$msg = sprintf(__('Your SoftWP plugin license is %1$snot authorized%2$s to be used on  %3$s. You can generate a new license for your domain from the %4$s panel.', 'softaculous-pro'), 
							'<b><font style="color:red;">',
							'</font></b>',
							'<b><i>'.site_url().'</i></b>',
							'<b>'.($softaculous_pro['branding']['sn'] == 'SoftWP' ? 'Softaculous' : $softaculous_pro['branding']['sn']).'</b>'
							);
			}elseif(empty($softaculous_pro['license']['active'])){
				$msg = sprintf(__('Your SoftWP plugin license has %1$sExpired%2$s. Please renew your license for uninterrupted updates and support.', 'softaculous-pro'), 
							'<font style="color:red;"><b>',
							'</b></font>'
							);
			}
		}
		
		if(!empty($msg)){
			echo '
			<div class="notice notice-error is-dismissible">
				<p>'.$msg.'</p>
			</div>';
		}
		
		// The notice to complete onboarding
		//$spro_is_shown = get_option('softaculous_pro_onboarding_shown');
		$spro_is_done = get_option('softaculous_pro_onboarding_done');
		$spro_is_dismissed = get_option('softaculous_pro_onboarding_notice_dismiss');
		
		if(empty($spro_is_done) && empty($spro_is_dismissed)){
			echo '
			<div class="notice notice-error is-dismissible" id="softaculous-onboarding-notice">
				<p>'.sprintf(__('Your Onboarding process is not completed yet! %1$sClick here%2$s to complete the simple setup process and build your site in a few steps.', 'softaculous-pro'),
							'<a href="'.admin_url('admin.php?page=assistant&act=onboarding').'" target="_blank">',
							'</a>').'</p>
			</div>
			<script type="text/javascript">
				jQuery(document).ready(function($){
					$("#softaculous-onboarding-notice").on("click", ".notice-dismiss", function() {
						// Send an AJAX request to the server to dismiss the notice
						jQuery.ajax({
							type: "post",
							url: softwp_obj.ajax_url,
							data: {
								action: "softaculous_pro_wp_ajax",
								softaculous_pro_onboarding_notice_dismiss: 1,
								softaculous_pro_security: softwp_obj.nonce,
								data: [],
							},
						});
					});
				});
			</script>
			';
			
			$spro_add_nonce_vars = 1;
		}
		
		$softwp_ai_is_dismissed = get_option('softaculous_pro_ai_notice_dismiss');
		
		if(empty($softwp_ai_is_dismissed) && !empty($_GET['page']) && $_GET['page'] == 'assistant'){
			echo '
			<div class="notice notice-info is-dismissible" id="softaculous-ai-notice">
				<h3 style="margin: 0.5em 0;">'.__('Enhance Content Writing with AI Assistant', 'softaculous-pro').'
				</h3>
				<p>'.__('Use cutting-edge AI to write blog posts or content for your pages. Create a table, write a paragraph, change tone, translate, fix spelling & grammar and so much more.', 'softaculous-pro').' <br />
				<b>'.__('Start Exploring', 'softaculous-pro').'</b> : 
				<a href="'.admin_url('post-new.php?post_type=page').'" target="_blank" style="text-decoration:none;">'.__('New Page', 'softaculous-pro').'</a>&nbsp; &#9679; &nbsp;
				<a href="'.admin_url('post-new.php').'" target="_blank" style="text-decoration:none;">'.__('New Post', 'softaculous-pro').'</a>&nbsp; &#9679; &nbsp;
				<a href="'.admin_url('edit.php?post_type=page').'" target="_blank" style="text-decoration:none;">'.__('Existing Page', 'softaculous-pro').'</a>&nbsp; &#9679; &nbsp;
				<a href="'.admin_url('edit.php').'" target="_blank" style="text-decoration:none;">'.__('Existing Post', 'softaculous-pro').'</a> 
				</p>
			</div>
			
			<script type="text/javascript">
				jQuery(document).ready(function($){
					$("#softaculous-ai-notice").on("click", ".notice-dismiss", function() {
						// Send an AJAX request to the server to dismiss the notice
						jQuery.ajax({
							type: "post",
							url: softwp_obj.ajax_url,
							data: {
								action: "softaculous_pro_wp_ajax",
								softaculous_pro_ai_notice_dismiss: 1,
								softaculous_pro_security: softwp_obj.nonce,
								data: [],
							},
						});
					});
				});
			</script>
			';
			
			$spro_add_nonce_vars = 1;
		}
		
		if(!empty($spro_add_nonce_vars)){
			
			echo '<script type="text/javascript">
			var softwp_obj = {
			  admin_url: "'.esc_url(admin_url()).'",
			  site_url: "'.esc_url(site_url()).'",
			  nonce: "'.wp_create_nonce('softaculous_pro_js_nonce').'",
			  ajax_url: "'.admin_url('admin-ajax.php').'"
			};
			</script>';
			
		}
		
	}
	
	return '';
}

function softaculous_pro_get_option($option_name, $default_value = false, $site_id = null){
	
    if($site_id !== null && is_multisite()){
        return get_site_option($option_name, $default_value);
    }
    return get_option($option_name, $default_value);
}

/**
 * Takes care of Slashes
 *
 * @param		string $string The string that will be processed
 * @return		string A string that is safe to use for Database Queries, etc
 * @since		1.0
 */
function softaculous_pro_inputsec($string){

	//get_magic_quotes_gpc is deprecated in php 7.4
	if(version_compare(PHP_VERSION, '7.4', '<')){
		if(!get_magic_quotes_gpc()){
		
			$string = addslashes($string);
		
		}else{
		
			$string = stripslashes($string);
			$string = addslashes($string);
		
		}
	}else{
		$string = addslashes($string);
	}
	
	// This is to replace ` which can cause the command to be executed in exec()
	$string = str_replace('`', '\`', $string);
	
	return $string;

}

/**
 * Converts Special characters to html entities
 *
 * @param        string $string The string containing special characters
 * @return       string A string containing special characters replaced by html entities of the format &#ASCIICODE;
 * @since     	 1.0
 */
function softaculous_pro_htmlizer($string){

	$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
	
	preg_match_all('/(&amp;#(\d{1,7}|x[0-9a-fA-F]{1,6});)/', $string, $matches);
	
	foreach($matches[1] as $mk => $mv){		
		$tmp_m = softaculous_pro_entity_check($matches[2][$mk]);
		$string = str_replace($matches[1][$mk], $tmp_m, $string);
	}
	
	return $string;
	
}

/**
 * Used in function htmlizer()
 *
 * @param        string $string
 * @return       string
 * @since     	 1.0
 */
function softaculous_pro_entity_check($string){
	
	//Convert Hexadecimal to Decimal
	$num = ((substr($string, 0, 1) === 'x') ? hexdec(substr($string, 1)) : (int) $string);
	
	//Squares and Spaces - return nothing 
	$string = (($num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF) || $num < 0x20) ? '' : '&#'.$num.';');
	
	return $string;
			
}

/**
 * OPTIONAL REQUEST of the given REQUEST Key
 *
 * @param        string $name The key of the $_REQUEST array i.e. the name of the input / textarea text 
 * @param        string $default The value to return if the $_REQUEST[$name] is NOT SET
 * @return       string Returns the string if the REQUEST is there otherwise the default value given.
 * @since     	 1.0
 */
function softaculous_pro_optREQ($name, $default = ''){

global $softaculous_error;

	//Check the POSTED NAME was posted
	if(isset($_REQUEST[$name])){
	
		return trim(sanitize_text_field($_REQUEST[$name]));
		
	}else{
		return $default;
	}
}

/**
 * OPTIONAL POST of the given POST Key
 *
 * @param        string $name The key of the $_POST array i.e. the name of the input / textarea text 
 * @param        string $default The value to return if the $_POST[$name] is NOT SET
 * @return       string Returns the string if the POST is there otherwise the default value given.
 * @since		1.4.6
 */
function softaculous_pro_optPOST($name, $default = ''){

global $softaculous_error;

	//Check the POSTED NAME was posted
	if(isset($_POST[$name])){
		
		if(is_array($_POST[$name])){
			$values = array_map('trim', $_POST[$name]);
			return array_map('sanitize_text_field', $values);
		}
	
		return trim(sanitize_text_field($_POST[$name]));
		
	}else{
		return $default;
	}

}

/**
 * OPTIONAL GET of the given GET Key i.e. dont throw a error if not there
 *
 * @param        string $name The key of the $_GET array i.e. the name of the input / textarea text 
 * @param        string $default The value to return if the $_GET[$name] is NOT SET
 * @return       string Returns the string if the GET is there otherwise the default value given.
 * @since     	 1.0
 */
function softaculous_pro_optGET($name, $default = ''){

global $softaculous_error;

	//Check the GETED NAME was GETed
	if(isset($_GET[$name])){
	
		return trim(sanitize_text_field($_GET[$name]));
		
	}else{
		return $default;
	}

}
	
function softaculous_pro_sp_api_url($main_server = 0){
	
	global $softaculous_pro;
	
	return softaculous_pro_api_url($main_server, 'sitepad');
	
}
	
function softaculous_pro_pfx_api_url($main_server = 0){
	
	global $softaculous_pro;
	
	return softaculous_pro_api_url($main_server, 'popularfx');
	
}
	
function softaculous_pro_api_url($main_server = 0, $suffix = ''){
	
	global $softaculous_pro;
	
	$r = array(
		'https://s0.softaculous.com/a/softwp/',
		'https://s1.softaculous.com/a/softwp/',
		'https://s2.softaculous.com/a/softwp/',
		'https://s3.softaculous.com/a/softwp/',
		'https://s4.softaculous.com/a/softwp/',
		'https://s5.softaculous.com/a/softwp/',
		'https://s7.softaculous.com/a/softwp/',
		'https://s8.softaculous.com/a/softwp/'
	);
	
	$mirror = $r[array_rand($r)];
	
	// If the license is newly issued, we need to fetch from API only
	if(!empty($main_server) || empty($softaculous_pro['license']['last_edit']) || 
		(!empty($softaculous_pro['license']['last_edit']) && (time() - 3600) < $softaculous_pro['license']['last_edit'])
	){
		$mirror = 'https://a.softaculous.com/softwp/';
	}
	
	// -1 indicates that we need to force the mirror server used for rendering static files e.g. screenshots
	if(!empty($main_server) && $main_server == '-1'){
		$mirror = $r[array_rand($r)];
	}
	
	if(!empty($suffix)){
		$mirror = str_replace('/softwp', '/'.$suffix, $mirror);
	}
	
	return $mirror;
	
}

// Load license data
function softaculous_pro_load_license(){
	
	global $softaculous_pro;

	// Load license
	$softaculous_pro['license'] = get_option('softaculous_pro_license', array());
	
	if(empty($softaculous_pro['license'])){
		return false;
	}
	
	$prods = apply_filters('softaculous_pro_products', []);
	
	// Update license details as well
	if(empty($softaculous_pro['license']['last_update']) || 
		(!empty($softaculous_pro['license']['last_update']) && (time() - $softaculous_pro['license']['last_update']) >= 86400)
	){
		
		$resp = wp_remote_get(softaculous_pro_api_url(1).'license.php?license='.$softaculous_pro['license']['license'].'&prods='.implode(',', $prods).'&url='.rawurlencode(site_url()));
		
		// Did we get a response ?
		if(is_array($resp)){
			
			$tosave = json_decode($resp['body'], true);
			
			// Is it the license ?
			if(!empty($tosave['license'])){
				$softaculous_pro['license'] = $tosave;
			}
			
		}
		
		// Save the old data only
		if(empty($tosave['license'])){
			$tosave = get_option('softaculous_pro_license', array());
		}
		
		$tosave['last_update'] = time();
		update_option('softaculous_pro_license', $tosave);
		
	}
	
	return $softaculous_pro['license'];
}

add_filter('softaculous_pro_products', 'softaculous_softwp_pro_products', 10, 1);
function softaculous_softwp_pro_products($r = []){
	$r['softwp'] = 'softwp';
	return $r;
}

// Load Softaculous rebranding settings
function softaculous_pro_rebranding(){
	
	global $softaculous_pro;
	
	$softaculous_pro['branding']['sn'] = 'SoftWP';
	$softaculous_pro['branding']['logo_url'] = SOFTACULOUS_PRO_PLUGIN_URL.'assets/images/logo-white.png';
	$softaculous_pro['branding']['rebranded'] = 0;

	//Getting info if Softaculous rebranding done or not?
	$soft_rebranding = get_option('softaculous_pro_rebranding', '[]');
	
	if(!empty($soft_rebranding['logo_url'])){
		$softaculous_pro['branding']['logo_url'] = $soft_rebranding['logo_url'];
	}
	
	if(!empty($soft_rebranding['sn']) && $soft_rebranding['sn'] != 'Softaculous'){
		$softaculous_pro['branding']['sn'] = $soft_rebranding['sn'];
		$softaculous_pro['branding']['rebranded'] = 1;
	}
	
	if(!empty($soft_rebranding['default_hf_bg'])){
		$softaculous_pro['branding']['default_hf_bg'] = $soft_rebranding['default_hf_bg'];
	}
	
	if(!empty($soft_rebranding['default_hf_text'])){
		$softaculous_pro['branding']['default_hf_text'] = $soft_rebranding['default_hf_text'];
	}
	
	return true;
}

// Add our license key if ANY
function softaculous_pro_updater_filter_args($queryArgs) {
	
	global $softaculous_pro;
	
	if ( !empty($softaculous_pro['license']['license']) ) {
		$queryArgs['license'] = $softaculous_pro['license']['license'];
	}
	
	return $queryArgs;
}

// Handle the Check for update link and ask to install license key
function softaculous_pro_updater_check_link($final_link){
	
	global $softaculous_pro;
	
	if(empty($softaculous_pro['license']['license'])){
		return '<a href="'.admin_url('admin.php?page=assistant&act=license').'">'.__('Enter Pro License Key', 'softaculous-pro').'</a>';
	}
	
	return $final_link;
}

function softaculous_pro_report_error($error = array()) {
	
	if(empty($error)){
		return true;
	}
	
	$error_string = '<b>' . esc_html__('Please fix the below error(s):', 'softaculous-pro') . '</b><br />';
	
	foreach($error as $ev){
		$error_string .= '* ' . esc_html($ev) . '<br />';
	}
	
	echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
}

function softaculous_pro_add_plugin_row_links($links, $slug) {

	if(is_multisite() && is_network_admin()){
		return $links;
	}

	if ($slug !== SOFTACULOUS_PRO_BASE) {
		return $links;
	}

	if(!current_user_can('activate_plugins')){
		return $links;
	}
	
	$new_links = array(
		'plugins' => '<a href="admin.php?page=assistant&act=manage-plugins"><font style="color:green;">'.__('Explore Pro Plugins', 'softaculous-pro').'</font></a>',
		'tours' => '<a href="admin.php?page=assistant#tours">'.__('Tour', 'softaculous-pro').'</a>',
		'ai' => '<a href="admin.php?page=assistant#ai"><font style="color:green;">'.__('AI', 'softaculous-pro').'</font></a>',
	);

	$links = array_merge($links, $new_links);

	return $links;
}

function softaculous_pro_add_params($link){
	
	global $softaculous_pro;
	
	$link = rtrim($link, '?&');

	$query = parse_url($link, PHP_URL_QUERY);

	if ($query) {
		$link .= '&';
	} else {
		$link .= '?';
	}

	$link .= 'version=latest&license='.$softaculous_pro['license']['license'].'&url='.site_url();
	
	return $link;
}

function softaculous_pro_register_post_type(){
	register_post_type(
		'spro_ai_history',
		[
			'labels' => [
				'name' => __('AI History', 'softaculous-pro'),
				'singular_name' => __('AI History', 'softaculous-pro'),
			],
			'public' => false,
			'map_meta_cap' => true,
			'hierarchical' => false,
			'rewrite' => false,
			'query_var' => false,
			'can_export' => false,
			'delete_with_user' => true,
			'supports' => array('author'),
		]
	);
}
intros.php000064400000052361151526435000006603 0ustar00<?php

if(!defined('ABSPATH')){
    exit;
}

$spro_tour_content = array();

////////////////////////////
// Assistant Tour
////////////////////////////

$spro_tour_content['assistant']['.spro-header-menu'] = array(
    "title" => __("Assistant", "softaculous-pro"),  
    "intro" => __("Assistant adds AI to your site building process and lets you create content with just a few clicks (look for the AI option while editing your posts/pages).", "softaculous-pro")
	.'<br /><br />'.
	__("Assistant also helps you with several aspects of building and maintaning your WordPress website.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['assistant']['#spro-tours'] = array(
    "title" => __("Tours", "softaculous-pro"),  
    "intro" => __("Tours highlights and explains important options in WordPress that you will need while managing your site.", "softaculous-pro")
	.'<br /><br />'.
	__("You can replay the tours when needed.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['assistant']['#spro-features'] = array(
    "title" => __("Recommended Features", "softaculous-pro"),  
    "intro" => __("A recommended list of plugins to improve performace and extend functionalties for your site.", "softaculous-pro"),
    "position" => "right", 
);

$spro_tour_content['assistant']['#spro-quick-links'] = array(
    "title" => __("Quick Links", "softaculous-pro"),  
    "intro" => __("Here you will find important links compiled in a single section which can sometimes be difficult to find in WordPress.", "softaculous-pro"),  
    "position" => "left", 
);

$spro_tour_content['assistant']['#spro-settings'] = array(
    "title" => __("Settings", "softaculous-pro"),  
    "intro" => __("We have simplified complex WordPress settings that you can now manage with just a click via the Assistant.", "softaculous-pro"),  
    "position" => "left", 
);

$spro_tour_content['assistant']['#spro-ai'] = array(
    "title" => __("AI", "softaculous-pro"),  
    "intro" => __("Experience hassle-free site building with inbuilt AI in Assistant.", "softaculous-pro"),
    "position" => "left", 
);

$spro_tour_content['assistant']['#toplevel_page_assistant'] = array(
    "title" => __("Your Assistant", "softaculous-pro"),  
    "intro" => __("Assistant resides here, when you are unable to find something or having a hard time understanding a feature in WordPress we should be able to help you.", "softaculous-pro")
	.'<br /><br />'.
	__("Visit this page anytime.", "softaculous-pro"),  
    "position" => "right", 
);

///////////////////////////////////
// WordPress Sidebar
///////////////////////////////////

$spro_tour_content['sidebar']['#toplevel_page_assistant'] = array(
    "title" => __("Your Assistant", "softaculous-pro"),  
    "intro" => __("Assistant resides here, when you are unable to find something or having a hard time understanding a feature in WordPress we should be able to help you.", "softaculous-pro")
	.'<br /><br />'.
	__("Visit this page anytime.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['sidebar']['#wp-admin-bar-view-site'] = array(
    "title" => __("Preview Site", "softaculous-pro"),  
    "intro" => __("You can use this link to preview your site as a visitor.", "softaculous-pro"),  
    "position" => "right",
    "hover" => "true",
    "hover_selector" => "#wp-admin-bar-site-name",
);

$spro_tour_content['sidebar']['#menu-dashboard'] = array(
    "title" => __("Dashboard", "softaculous-pro"),  
    "intro" => __("The Dashboard is your website's command center, providing a concise summary of its activity, such as site health, recent updates, comments, and statistics.", "softaculous-pro")
	.'<br /><br />'.
	__("Several plugins also display quick summary like orders, products, etc within the dashboard.", "softaculous-pro")
	.'<br /><br />'.
	__("You can also check for Updates from the sub-menu.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['sidebar']['#menu-posts'] = array(
    "title" => __("Posts", "softaculous-pro"),  
    "intro" => __("Manage your blog posts here.", "softaculous-pro")
	.'<br /><br />'.
	__("Posts are typically utilized for blog posts, news updates, or articles, organized in a chronological order.", "softaculous-pro"),
    "position" => "right", 
); 

$spro_tour_content['sidebar']['#menu-media'] = array(
    "title" => __("Media Library", "softaculous-pro"),  
    "intro" => __("Manage media files like images, audio, videos, etc. here.", "softaculous-pro")
	.'<br /><br />'.
	__("Media uploaded from anywhere on your site can be managed here.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['sidebar']['#menu-pages'] = array(
    "title" => __("Pages", "softaculous-pro"),
    "intro" => __("Pages are static content sections such as Home, About Us, Contact, Services, etc.", "softaculous-pro")
	.'<br /><br />'.
	__("Use this menu to add, edit, delete your pages.", "softaculous-pro"),
    "position" => "right", 
); 

$spro_tour_content['sidebar']['#menu-comments'] = array(
    "title" => __("Comments", "softaculous-pro"),  
    "intro" => __("Here you can moderate comments posted by visitors on your posts.", "softaculous-pro")
	.'<br /><br />'.
	__("You can one click disable comments for your entire site from the Assistant dashboard.", "softaculous-pro"),
    "position" => "right", 
); 

$spro_tour_content['sidebar']['#menu-appearance'] = array(
    "title" => __("Appearance", "softaculous-pro"),
    "intro" => __("Personalize your site's appearance effortlessly.", "softaculous-pro")
	.'<br /><br />'.
	__("Explore themes, customize headers, background, colors, manage widgets and menus to customize your site's look and feel.", "softaculous-pro"),  
    "position" => "right", 
); 

$spro_tour_content['sidebar']['#menu-plugins'] = array(
    "title" => __("Plugins", "softaculous-pro"),
    "intro" => __("Unlock endless possibilities for your website with plugins.", "softaculous-pro")
	.'<br /><br />'.
	__("Easily search, add or delete plugins to enhance your site's functionality.", "softaculous-pro"),  
    "position" => "right", 
); 

$spro_tour_content['sidebar']['#menu-users'] = array(
    "title" => __("Users", "softaculous-pro"),
    "intro" => __("Add or manage users to ensure smooth operation and collaboration.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['sidebar']['#menu-tools'] = array(
    "title" => __("Tools", "softaculous-pro"),
    "intro" => __("Import/Export site data, check site health or edit plugin/theme files from the Tools menu.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['sidebar']['#menu-settings'] = array(
    "title" => __("Settings", "softaculous-pro"),
    "intro" => __("Advanced settings for your site can be managed here.", "softaculous-pro")
	.'<br /><br />'.
	__("These settings include site title, tagline, site url, writing, reading, discussion, media, permalinks and more.", "softaculous-pro")
	.'<br /><br />'.
	__("Some plugins also add their settings page in this menu.", "softaculous-pro"),
    "position" => "right", 
);

$spro_tour_content['sidebar']['#collapse-menu'] = array(
    "title" => __("Toggle Menu", "softaculous-pro"),
    "intro" => __("Expand or Collapse the sidebar menu using this option.", "softaculous-pro"),
    "position" => "right", 
);

$spro_tour_content['sidebar']['#wp-admin-bar-user-info'] = array(
    "title" => __("Edit Profile", "softaculous-pro"),  
    "intro" => __("Here you can edit your profile information like name, email, password, bio, profile picture and more.", "softaculous-pro"),  
    "position" => "left",
    "hover" => "true",
    "hover_selector" => "#wp-admin-bar-my-account",
);

$spro_tour_content['sidebar']['#wp-admin-bar-logout'] = array(
    "title" => __("Log Out", "softaculous-pro"),  
    "intro" => __("Use this link to securely log out from your site.", "softaculous-pro"),
    "position" => "left",
    "hover" => "true",
    "hover_selector" => "#wp-admin-bar-my-account",
);

////////////////////////////
// Plugins Page
////////////////////////////

$spro_tour_content['plugins']['#menu-plugins'] = array(
    "title" => __("Plugins", "softaculous-pro"),  
    "intro" => __("Click here to add or manage plugins on your site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['plugins']['.page-title-action'] = array(
    "title" => __("Add New Plugin", "softaculous-pro"),  
    "intro" => __("Here you can search wordpress.org plugins library or upload a custom plugin file to install a new plugin on your site.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['plugins']['tr[data-plugin]'] = array(
    "title" => __("Installed Plugins List", "softaculous-pro"),  
    "intro" => __("All your installed plugins active as well as inactive will be listed here.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['plugins']['td.plugin-title'] = array(
    "title" => __("Plugin Actions", "softaculous-pro"),  
    "intro" => __("You can perform actions for your plugins like Activate, Deactivate, Update, Delete, Plugin Settings and more..", "softaculous-pro")
	.'<br /><br />'.
	__("It is recommended to delete plugins that you do not plan to use and keep all your plugins up to date.", "softaculous-pro"),  
    "position" => "bottom",
);

$spro_tour_content['plugins']['#bulk-action-selector-top'] = array(
    "title" => __("Bulk Actions", "softaculous-pro"),  
    "intro" => __("Choose bulk action for selected plugins: Activate, Deactivate, Update, Delete, toggle auto updates and more", "softaculous-pro"), 
    "position" => "bottom", 
);

$spro_tour_content['plugins']['.subsubsub'] = array(
    "title" => __("Filter Installed Plugins", "softaculous-pro"),  
    "intro" => __("Filter your installed plugins list with Active, Inactive, Auto Updates Enabled or Disabled options", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['plugins']['#plugin-search-input'] = array(
    "title" => __("Search Installed Plugins", "softaculous-pro"),  
    "intro" => __("Search a plugin from the installed plugins list.", "softaculous-pro"),
    "position" => "bottom",
);

////////////////////////////
// Themes Page
//////////////////////////// 

$spro_tour_content['themes']['#menu-appearance'] = array(
    "title" => __("Themes", "softaculous-pro"),
    "intro" => __("Click here to add or manage themes on your site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['themes']['.page-title-action'] = array(
    "title" => __("Add New Theme", "softaculous-pro"),  
    "intro" => __("Here you can search wordpress.org themes library or upload a custom theme file to install a new theme on your site.", "softaculous-pro"),
    "position" => "bottom", 
);

$spro_tour_content['themes']['.theme-browser'] = array(
    "title" => __("Installed Themes List", "softaculous-pro"),  
    "intro" => __("All your installed themes active as well as inactive will be listed here.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['themes']['.theme.active[data-slug]'] = array(
    "title" => __("Active Theme", "softaculous-pro"),  
    "intro" => __("Your active theme will be listed here.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['themes']['.theme-actions'] = array(
    "title" => __("Theme Actions", "softaculous-pro"),  
    "intro" => __("You can perform actions for your theme like Activate, Live Preview, Customize and more", "softaculous-pro")
	.'<br /><br />'.
	__("It is recommended to delete themes that you do not plan to use and keep all your themes up to date.", "softaculous-pro"),  
    "position" => "bottom",
);

$spro_tour_content['themes']['.search-box'] = array(
    "title" => __("Search Installed Themes", "softaculous-pro"),  
    "intro" => __("Search a theme from the installed themes list.", "softaculous-pro"),
    "position" => "bottom",
);

////////////////////////////
// WordPress Dashboard Page
////////////////////////////

$spro_tour_content['dashboard']['#menu-dashboard'] = array(
    "title" => __("Dashboard", "softaculous-pro"),  
    "intro" => __("The Dashboard is your website's command center, providing a concise summary of its activity, such as site health, recent updates, comments, and statistics.", "softaculous-pro")
	.'<br /><br />'.
	__("Several plugins also display quick summary like orders, products, etc within the dashboard.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['dashboard']['#dashboard_site_health'] = array(
    "title" => __("Site Health", "softaculous-pro"),  
    "intro" => __("Here you can get insights on the overall performance and security of your website.", "softaculous-pro")
	.'<br /><br />'.
	__("It offers recommendations and troubleshooting tools to help you maintain an efficient and secure site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['dashboard']['#dashboard_right_now'] = array(
    "title" => __("Info at a Glance", "softaculous-pro"),  
    "intro" => __("Here you will get the number of posts, pages, comments, current version of WordPress and theme that you are running.", "softaculous-pro"),
    "position" => "right", 
);

$spro_tour_content['dashboard']['#dashboard_activity'] = array(
    "title" => __("Activity", "softaculous-pro"),  
    "intro" => __("Here you will get a quick summary of recent activity like published posts and comments received on your site.", "softaculous-pro"),  
    "position" => "right", 
);


$spro_tour_content['dashboard']['#dashboard_quick_press'] = array(
    "title" => __("Quick Draft", "softaculous-pro"),  
    "intro" => __("Use this section for capturing ideas as they come to you, quickly jot down the ideas for new posts.", "softaculous-pro")
	.'<br /><br />'.
	__("You can later access these drafts from the Posts section and continue editing them in the full post editor.", "softaculous-pro"),
    "position" => "left", 
);


$spro_tour_content['dashboard']['#dashboard_primary'] = array(
    "title" => __("Events and News", "softaculous-pro"),  
    "intro" => __("This widget is a valuable resource for staying informed about the latest happenings in the WordPress community and connecting with other WordPress enthusiasts.", "softaculous-pro")
	.'<br /><br />'.
	__("Here you will find updates on new releases, upcoming features, security updates, and general news about the WordPress community.", "softaculous-pro")
	.'<br /><br />'.
	__("This section also shows upcoming WordPress events such as WordCamps, local meetups, and other community gatherings.", "softaculous-pro"),
    "position" => "left", 
);


$spro_tour_content['dashboard']['#screen-options-link-wrap'] = array(
    "title" => __("Screen Options", "softaculous-pro"),  
    "intro" => __("This useful feature allows you to select the screen elements that you would like to show or hide by using the checkboxes.", "softaculous-pro")
	.'<br /><br />'.
	__("You will find this option on several pages across your site.", "softaculous-pro"),
    "position" => "bottom", 
);

////////////////////////////
// Users Page
////////////////////////////

$spro_tour_content['users']['#menu-users'] = array(
    "title" => __("Users", "softaculous-pro"),  
    "intro" => __("Click here to add or manage users on your site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['users']['.page-title-action'] = array(
    "title" => __("Add New User", "softaculous-pro"),  
    "intro" => __("Add a new user for your site. You can enter user details, password, role, etc.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['users']['tbody > tr'] = array(
    "title" => __("Users List", "softaculous-pro"),  
    "intro" => __("All your users with admin role as well as other roles will be listed here.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['users']['tbody > tr > td'] = array(
	"title" => __("Edit User", "softaculous-pro"),
	"intro" => __("You can edit the user information, change password, change role and much more with the Edit link here.", "softaculous-pro"),
	"position" => "bottom",
	"hover" => "true",
	"hover_selector" => ".row-actions",
	"hover_class" => "visible",
);

$spro_tour_content['users']['#bulk-action-selector-top'] = array(
    "title" => __("Bulk Actions", "softaculous-pro"),  
    "intro" => __("Choose bulk action for selected users: Delete or send password reset link", "softaculous-pro"), 
    "position" => "bottom", 
);

$spro_tour_content['users']['#new_role'] = array(
    "title" => __("Change Role", "softaculous-pro"),  
    "intro" => __("Here you can bulk change role for the selected users", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['users']['.subsubsub'] = array(
    "title" => __("Filter Users", "softaculous-pro"),  
    "intro" => __("Filter your users list with their roles", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['users']['.search-box'] = array(
    "title" => __("Search Users", "softaculous-pro"),  
    "intro" => __("Search a user from the users list.", "softaculous-pro"),
    "position" => "bottom",
);

////////////////////////////
// Posts Page
////////////////////////////

$spro_tour_content['posts']['#menu-posts'] = array(
    "title" => __("Posts", "softaculous-pro"),  
    "intro" => __("Click here to add or manage blog posts on your site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['posts']['.page-title-action'] = array(
    "title" => __("Add New Post", "softaculous-pro"),  
    "intro" => __("Start writing a new blog post for your site.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['posts']['tbody > tr'] = array(
    "title" => __("Posts List", "softaculous-pro"),  
    "intro" => __("All the posts owned by all the users on your site will be listed here.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['posts']['tbody > tr > td'] = array(
    "title" => __("Manage Post", "softaculous-pro"),  
    "intro" => __("You can view, edit or delete the posts with the links here.", "softaculous-pro"),
    "position" => "bottom",
    "hover" => "true",
    "hover_selector" => ".row-actions",
    "hover_class" => "visible"
);

$spro_tour_content['posts']['#bulk-action-selector-top'] = array(
    "title" => __("Bulk Actions", "softaculous-pro"),  
    "intro" => __("Choose bulk action for selected posts: Quick Edit or Move to Trash.", "softaculous-pro"), 
    "position" => "bottom", 
);

$spro_tour_content['posts']['#filter-by-date'] = array(
    "title" => __("Filter Posts by Date", "softaculous-pro"),  
    "intro" => __("Here you can filter the posts by date.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['posts']['#cat'] = array(
    "title" => __("Filter Posts by Category", "softaculous-pro"),  
    "intro" => __("Here you can filter the posts by category.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['posts']['.subsubsub'] = array(
    "title" => __("Filter Posts", "softaculous-pro"),  
    "intro" => __("Filter your posts list by their status like published, drafts, trash, etc.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['posts']['.search-box'] = array(
    "title" => __("Search Posts", "softaculous-pro"),  
    "intro" => __("Search a post from the posts list.", "softaculous-pro"),
    "position" => "bottom",
);

////////////////////////////
// Pages Page
////////////////////////////

$spro_tour_content['pages']['#menu-pages'] = array(
    "title" => __("Pages", "softaculous-pro"),  
    "intro" => __("Click here to add or manage pages on your site.", "softaculous-pro"),  
    "position" => "right", 
);

$spro_tour_content['pages']['.page-title-action'] = array(
    "title" => __("Add New Page", "softaculous-pro"),  
    "intro" => __("Start creating a new page for your site.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['pages']['tbody > tr'] = array(
    "title" => __("Pages List", "softaculous-pro"),  
    "intro" => __("All the pages on your site will be listed here.", "softaculous-pro"),
    "position" => "bottom", 
);

$spro_tour_content['pages']['tbody > tr > td'] = array(
    "title" => __("Manage Page", "softaculous-pro"),  
    "intro" => __("You can view, edit or delete the pages with the links here.", "softaculous-pro"),
    "position" => "bottom",
    "hover" => "true",
    "hover_selector" => ".row-actions",
    "hover_class" => "visible"
);

$spro_tour_content['pages']['#bulk-action-selector-top'] = array(
    "title" => __("Bulk Actions", "softaculous-pro"),  
    "intro" => __("Choose bulk action for selected pages: Quick Edit or Move to Trash.", "softaculous-pro"), 
    "position" => "bottom", 
);

$spro_tour_content['pages']['#filter-by-date'] = array(
    "title" => __("Filter Pages by Date", "softaculous-pro"),  
    "intro" => __("Here you can filter the pages by date.", "softaculous-pro"),  
    "position" => "bottom", 
);

$spro_tour_content['pages']['.subsubsub'] = array(
    "title" => __("Filter Pages", "softaculous-pro"),  
    "intro" => __("Filter your pages list by their status like published, drafts, trash, etc.", "softaculous-pro"),
    "position" => "bottom",
);

$spro_tour_content['pages']['.search-box'] = array(
    "title" => __("Search Pages", "softaculous-pro"),  
    "intro" => __("Search a page from the pages list.", "softaculous-pro"),
    "position" => "bottom",
);

ai.php000064400000021533151526435000005653 0ustar00<?php

namespace SoftWP;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT');
}

class AI{

	static function enqueue_scripts(){
		
		global $softaculous_pro;

		wp_enqueue_style('softaculous-pro-ai', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/css/ai.css', [], SOFTACULOUS_PRO_VERSION);

		wp_enqueue_script('softaculous_ai_base', SOFTACULOUS_PRO_PLUGIN_URL . 'assets/js/ai/ai.js', ['jquery'], SOFTACULOUS_PRO_VERSION, ['strategy' => 'defer']);

		$soft_ai = [
			'i18n' => [],
			'nonce' => wp_create_nonce('softaculous_ai_nonce'),
			'ajax_url' => admin_url('admin-ajax.php'),
			'ai_icon_url' => SOFTACULOUS_PRO_PLUGIN_URL .'/assets/images/softaculous-ai.svg',
			'buy' => esc_url(SOFTACULOUS_PRO_AI_BUY.'&softwp_lic='.$softaculous_pro['license']['license'])
		];
		
		$tokens = get_option('softaculous_ai_tokens', []);
		if(!empty($tokens)){
			$soft_ai['tokens'] = $tokens;
		}

		wp_localize_script('softaculous_ai_base', 'soft_ai', $soft_ai);
		
		// Loading the assets data
		$asset_file = [];
		$asset_file = include_once(SOFTACULOUS_PRO_PLUGIN_PATH . 'assets/js/ai/build/index.asset.php');
		if(is_array($asset_file)){
			array_push($asset_file['dependencies'], 'softaculous_ai_base'); // Adding the ai base js dep
		}

		wp_enqueue_script(
			'softaculous_ai_gb',
			SOFTACULOUS_PRO_PLUGIN_URL . 'assets/js/ai/build/index.js', // Load from the build directory
			$asset_file['dependencies'],
			$asset_file['version'],
			['strategy' => 'defer']
		);	
		
		// The API provides better output as markdown compared to html, thats why we need this markdown library to convert the markdown to html.
		wp_enqueue_script(
			'softaculous_ai_marked',
			SOFTACULOUS_PRO_PLUGIN_URL . 'assets/js/marked.min.js',
			array('softaculous_ai_base'),
			SOFTACULOUS_PRO_VERSION,
			['strategy' => 'defer']
		);
	}
	
	static function generate(){
		global $softaculous_pro, $softaculous_pro_settings;
		
		check_admin_referer('softaculous_ai_nonce', 'nonce');
		
		if(!current_user_can('manage_options')){
			wp_send_json_error(__('You do not have required privilege', 'softaculous-pro'));
		}
		
		set_time_limit(100);
		
		$content = !empty($_REQUEST['content']) ? wp_kses_post(wp_unslash($_REQUEST['content'])) : '';
		$prompt = !empty($_REQUEST['prompt']) ? wp_kses_post(wp_unslash($_REQUEST['prompt'])) : '';
		$shortcut = !empty($_REQUEST['shortcut']) ? sanitize_text_field(wp_unslash($_REQUEST['shortcut'])) : '';
		$license = !empty($softaculous_pro['license']['license']) ? $softaculous_pro['license']['license'] : '';

		if(empty($license)){
			wp_send_json_error(__('Please link a license to keep using the AI feature', 'softaculous-pro'));
		}
		
		// We need atleast a prompt or a shortcut
		if(empty($prompt) && empty($shortcut)){
			wp_send_json_error(__('Please write a Prompt, for the AI to generate content', 'softaculous-pro'));
		}
		
		// Shortcut requires content, but a prompt does not,
		// shortcuts are meant to be used to process content,
		// where as a Prompt can be used to process as well as generate content.
		if(!empty($shortcut) && empty($content)){
			wp_send_json_error(__('AI shortcut can not be applied without any content.', 'softaculous-pro'));
		}

		$res = wp_remote_post(SOFTACULOUS_PRO_AI_API, [
			'timeout' => 90,
			'body' => [
				'prompt' => $prompt,
				'shortcut' => $shortcut,
				'content' => $content,
				'license' => $license,
				'url' => site_url()
			]
		]);

		if(empty($res)){
			wp_send_json_error(__('Unable to complete this request', 'softaculous-pro'));
		}
		
		if(is_wp_error($res)){
			$error_string = $res->get_error_message();
			wp_send_json_error($error_string);
		}

		$res_code = wp_remote_retrieve_response_code($res);
		$body = wp_remote_retrieve_body($res);
		
		if(empty($body)){
			wp_send_json_error(__('The AI API responsed with empty response, Response Code:', 'softaculous-pro') . $res_code);
		}

		$ai_content = json_decode($body, true);

		if($res_code > 299){
			$error = !empty($ai_content['error']) ? sanitize_text_field($ai_content['error']) : __('Unexpected response code returned from AI API: ', 'softaculous-pro') . $res_code;
			
			wp_send_json_error($error);
		}

		// Building the history data
		if(!isset($ai_content['error']) && isset($softaculous_pro_settings['ai_history_duration']) && $softaculous_pro_settings['ai_history_duration'] > 0 && !empty($ai_content['ai'])){
			$history_data = [];
			if(!empty($content)){
				$history['content'] = wp_kses_post(wp_unslash($content));
				$title = (strlen($content) > 100 ? substr($content, 100) : $content);
			}

			if(!empty($prompt)){
				$history['prompt'] = wp_kses_post(wp_unslash($prompt));
				$title = (strlen($prompt) > 100 ? substr($prompt, 100) : $prompt);
			}

			if(empty($prompt) && !empty($shortcut)){
				$history['shortcut'] = sanitize_text_field($shortcut);
				$title = self::parse_shortcuts($shortcut);
			}

			if(!empty($ai_content['ai'])){
				$history['assistant'] = wp_kses_post(wp_unslash($ai_content['ai']));
			}
			
			if(!empty($ai_content['total_tokens'])){
				$title .= '|||'.$ai_content['total_tokens'];
			}

			// Saving the history
			wp_insert_post([
				'post_title' => sanitize_text_field($title),
				'post_type' => 'spro_ai_history',
				'post_content' => serialize($history),
			]);
		}

		// Saving token data
		if(!empty($ai_content['remaining_tokens'])){
			update_option('softaculous_ai_tokens', [
				'remaining_tokens' => sanitize_text_field($ai_content['remaining_tokens'])
			], false);
		}
		
		wp_send_json_success($ai_content);

	}
	
	static function load_history(){
		check_admin_referer('softaculous_ai_nonce', 'nonce');

		if(!current_user_can('manage_options')){
			wp_send_json_error(__('You do not have required privilege', 'softaculous-pro'));
		}
		
		$history_id = !empty($_POST['history_id']) ? sanitize_text_field(wp_unslash($_POST['history_id'])) : 0;
		$offset = !empty($_POST['offset']) ? (int) sanitize_text_field(wp_unslash($_POST['offset'])) : 0;
		$history = [];
		
		if(!empty($history_id)){
			$query = new \WP_Query([
				'post_type' => ['spro_ai_history'],
				'page_id' => $history_id,
			]);
			
			if($query->have_posts()){
				while($query->have_posts()){
					$query->the_post();
					$history = unserialize(get_the_content());
				}
			}
			
			// Restore to original post
			wp_reset_postdata();
			wp_send_json_success($history);
			
		} else {
			$query = new \WP_Query([
				'post_type' => ['spro_ai_history'],
				'posts_per_page' => 20,
				'offset' => $offset,
				'orderby' => 'date',
				'order' => 'DESC',
			]);
		}

		if($query->have_posts()){
			while($query->have_posts()){
				$query->the_post();
				$single['token_used'] = 0;
				$single['title'] = get_the_title();
				$single['date'] = get_the_date();
				$single['id'] = get_the_ID();
				
				if(strpos($single['title'], '|||') !== FALSE) {
					$get_count = explode('|||', $single['title']);
					$single['title'] = $get_count[0];
					$single['token_used'] = $get_count[1];
				}

				array_push($history, $single);
			}
		}
		
		// Restore to original post
		wp_reset_postdata();
		
		$total_count = wp_count_posts('spro_ai_history')->draft; // Getting the total count
		wp_send_json_success(['history' => $history , 'total' => $total_count]);
	}
	
	static function parse_shortcuts($shortcut){
		$supported_languages = ['arabic', 'chinese', 'czech', 'danish', 'dutch', 'english', 'finnish', 'french', 'german', 'greek', 'hindi', 'hebrew', 'hungarian', 'indonesian', 'italian', 'japanese', 'korean', 'marathi', 'punjabi', 'persian', 'polish', 'portuguese', 'russian', 'spanish', 'swedish', 'thai', 'turkish', 'vietnamese'];
		$supported_tones = ['casual', 'confidence', 'formal', 'friendly', 'inspirational', 'motivational', 'nostalgic', 'playful', 'professional', 'scientific', 'straightforward', 'witty'];
		$other_shortcuts = ['shorter' => 'Make it shorter', 'longer' => 'Make it longer', 'simplify' => 'Simplify the language', 'grammar' => 'Fix Spelling and Grammar'];
		
		if(in_array($shortcut, $supported_languages)){
			return 'Translate to ' . ucfirst($shortcut);
		}
		
		if(in_array($shortcut, $supported_tones)){
			return 'Change the tone of the content to ' . ucfirst($shortcut);
		}
		
		if(array_key_exists($shortcut, $other_shortcuts)){
			return $other_shortcuts[$shortcut];
		}

		return $shortcut;
	}
	
	static function delete_history($delete_all = false){

		$settings = get_option('softaculous_pro_settings', []);
		$history_duration = (int) $settings['ai_history_duration'];

		// If it is off then we wont delete the history.
		if($history_duration < 1){
			return;
		}

		$x_days_ago = date('Y-m-d', strtotime('-'.$history_duration.' days'));

		$query = new \WP_Query([
			'post_type' => 'spro_ai_history',
			'post_status' => 'draft',
			'date_query'=> [
				[
					'column' => 'post_date',
					'before' => $x_days_ago,
				],
			],
			'posts_per_page' => 100,
		]);

		if($query->have_posts()){
			while($query->have_posts()){
				$query->the_post();
				wp_delete_post(get_the_ID(), true);
			}

			wp_reset_postdata();
		}
	}
	
}
manage-plugins.php000064400000010767151526435000010200 0ustar00<?php

//////////////////////////////////////////////////////////////
//===========================================================
// license.php
//===========================================================
// softaculous-pro
// Inspired by the DESIRE to be the BEST OF ALL
// ----------------------------------------------------------
// Started by: Pulkit Gupta
// Date:	   12 Sep 2024
// Time:	   23:00 hrs
// Site:	   https://www.softaculous.com/
// ----------------------------------------------------------
// Please Read the Terms of use at http://softaculous.com/
// ----------------------------------------------------------
//===========================================================
// (c)softaculous Team
//===========================================================
//////////////////////////////////////////////////////////////

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

if(defined('SOFTACULOUS_PRO_VERSION')) {
	return;
}

function softaculous_pro_manage_plugins(){
	
	global $spro_error;
	
	softaculous_pro_header(0);
	
	include_once(SOFTACULOUS_PRO_PLUGIN_PATH.'main/onboarding.php');
	$spro_manage_features = spro_get_features_list();
	
	$manage_installed_plugins = get_plugins();
	
	if(!empty($softaculous_pro_error)){
		echo '<div id="message" class="error"><p>'.esc_html($softaculous_pro_error).'</p></div>';
	}
	
	if(!empty($softaculous_pro_msg)){
		echo '<div id="message" class="updated"><p>'.esc_html($softaculous_pro_msg).'</p></div>';
	}
	
	echo '
	<div class="spro-box-heading"><h3 class="smb-2 spb-1 sml-2">
		'.__('Manage Plugins', 'softaculous-pro').'</h3>
		<hr />
		<br />
	</div>
	
	<div class="spro-container">
	<div class="srow">';
		foreach($spro_manage_features as $feature => $info){
			foreach($info['plugin'] as $pslug => $data){
				
				if(empty($data['featured'])) continue;
				
				$disabled = '';
				if (!empty($data['requires_php']) && version_compare(PHP_VERSION, $data['requires_php'], '<')) {
					$data['plugin_desc'] .= '<br><span style="color: red;">'.sprintf(__('Requires PHP version %1$s or higher', 'softaculous-pro'), $data['requires_php']).'</span>';
					$disabled ='disabled';
				}
				
				echo '
				<div class="scol-6 spro-box-holder">
				<div class="spro-mng-plugin-header spx-2">
					<img src="'.(!empty($data['plugin_img']) ? $data['plugin_img'] : SOFTACULOUS_PRO_PLUGIN_URL.'/assets/images/plugins/'.$pslug.'.png').'" width="50" />
					<div class="spro-plugin-info-con sp-2">
						<div class="spro-manage-plugin-title spx-2">'.$data['plugin_name'].'</div>
						<div class="sp-2 spro-manage-plugin-desc">'.$data['plugin_desc'].'</div>
					</div>
				</div>
				<div class="spro-rec-plugin spx-2 smy-1">';
				
				$i_pending = $a_pending = 0;
				if(!empty($data['plugin_init'])){
				
					if(empty($manage_installed_plugins[$data['plugin_init']])){
						$status_free = __('Not Installed', 'softaculous-pro');
						$i_pending = 1;
					}elseif(!is_plugin_active($data['plugin_init'])){
						$status_free = __('Installed', 'softaculous-pro');
						$a_pending = 1;
					}else{
						$status_free = __('Active', 'softaculous-pro');
					}
				
					echo '<span class="spro-status"><b>'.__('Free', 'softaculous-pro').'</b>: '.$status_free.'</span>';
					
				}
				
				if(!empty($data['plugin_init_pro'])){
				
					if(empty($manage_installed_plugins[$data['plugin_init_pro']])){
						$status_pro = __('Not Installed', 'softaculous-pro');
						$i_pending = 1;
					}elseif(!is_plugin_active($data['plugin_init_pro'])){
						$status_pro = __('Installed', 'softaculous-pro');
						$a_pending = 1;
					}else{
						$status_pro = __('Active', 'softaculous-pro');
					}
				
					echo '<br /><span class="spro-status"><b>'.__('Pro', 'softaculous-pro').'</b>: '.$status_pro.'</span>';
				}
				
				echo '<span style="float:right;">';
				if(!empty($i_pending)){
					echo '<input type="button" name="'.$pslug.'" class="spro-plugin-install-btn sp-2" value="'.__('Install for Free', 'softaculous-pro').'" '.$disabled.'>';
				}elseif(!empty($a_pending)){
					echo '<input type="submit" name="'.$pslug.'" class="spro-plugin-install-btn spro-active-plugin sp-2" value="'.__('Activate', 'softaculous-pro').'" '.$disabled.'>';
				}else{
					echo '<p class="spro-plugin-active"><i class="fa-solid fa-check"></i>&nbsp;'.__('Active', 'softaculous-pro').'</p>';
				}
				echo '</span>';
				
				
				echo '
				</div>
				<i style="color:green;" class="spl-2">'.__('Pro included with your subscription', 'softaculous-pro').'</i>
				</div>';
			}
	}
	echo '
	</div>
	</div>';
	softaculous_pro_footer();
	
}
onboarding.php000064400000147353151526435000007415 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

add_action('admin_print_styles', 'softaculous_pro_admin_print_styles');
function softaculous_pro_admin_print_styles() {
	
	$act = softaculous_pro_optGET('act');
	$page = softaculous_pro_optGET('page');
	
	// Check if the current page is the onboarding wizard
	if($page == 'assistant' && $act == 'onboarding'){
		echo '<style>
			#adminmenuback, #adminmenuwrap, #wpadminbar  { display: none !important; }
		</style>';
	}
}

add_action('admin_menu', 'softaculous_pro_onboarding_admin_menu', 6);
function softaculous_pro_onboarding_admin_menu() {

	$capability = 'activate_plugins';
	
	// Onboarding
	//add_submenu_page('assistant', __('Onboarding', 'softaculous-pro'), __('Onboarding', 'softaculous-pro'), $capability, 'softaculous_pro_onboarding', 'softaculous_pro_page_handler');
	
	$act = softaculous_pro_optGET('act');
	$page = softaculous_pro_optGET('page');
	
	// Check if the current page is the onboarding wizard
	if($page == 'assistant' && $act == 'onboarding'){
		// Remove admin menu
		remove_menu_page('index.php'); // Dashboard
		remove_menu_page('edit.php'); // Posts
		remove_menu_page('upload.php'); // Media
		remove_menu_page('edit.php?post_type=page'); // Pages
		remove_menu_page('edit-comments.php'); // Comments
		remove_menu_page('themes.php'); // Appearance
		remove_menu_page('plugins.php'); // Plugins
		remove_menu_page('users.php'); // Users
		remove_menu_page('tools.php'); // Tools
		remove_menu_page('options-general.php'); // Settings
		add_filter('show_admin_bar', '__return_false');
		remove_filter('update_footer', 'core_update_footer');
		add_filter('screen_options_show_screen', '__return_false');
		add_filter('admin_footer_text', '__return_empty_string');
		remove_all_actions( 'admin_notices' );
		remove_all_actions( 'all_admin_notices');
	}

}

// Add the action to load the plugin 
add_action('plugins_loaded', 'softaculous_pro_onboarding_load_plugin');

// The function that will be called when the plugin is loaded
function softaculous_pro_onboarding_load_plugin(){

	global $pagelayer, $softaculous_pro;
	
	add_action('admin_enqueue_scripts', 'softaculous_pro_onboarding_enqueue_scripts');

	/* // Load the freemium widgets
	if(!defined('PAGELAYER_PREMIUM')){
		add_action('pagelayer_load_custom_widgets', 'spro_freemium_shortcodes');
	} */
	
	// Are we to setup a template ?
	$slug = get_option('softaculous_pro_setup_template');
	if(!empty($slug)){
		add_action('after_setup_theme', 'spro_setup_template_import');
	}

}

function softaculous_pro_onboarding_enqueue_scripts(){	
			
	$softwp_onboarding_lang = array(
		'conf_data_loss' => __( 'Please confirm that you accept data loss since you have already run the onboarding process previously', 'softaculous-pro' ),
		'select_atleast_one' => __( 'Please select atleast one page to import', 'softaculous-pro' ),
		'downloading_installing_plugins' => __( "Downloading and installing required plugins", 'softaculous-pro' ),
		'wordpress_require_ftp' => __( "WordPress requires FTP details, without them you won't be able to install a plugin/theme", 'softaculous-pro' ),		
		'downloading_template' => __( "Downloading the template", 'softaculous-pro' ),
		'buildWebsite' => __( 'Building your website...', 'softaculous-pro' ),
		'checkRequirements' => __( 'Checking the requirements ...', 'softaculous-pro' ),
		'importTemplate' => __( 'Importing the template', 'softaculous-pro' ),
		'setupCompleted' => __( 'Your website setup is completed', 'softaculous-pro' ),
		'congratulations' => __( 'Congratulations', 'softaculous-pro'),
	);

	if(!empty($_GET['act']) && $_GET['act'] === 'onboarding') {
		
		wp_enqueue_script('softaculous-pro-script-onboarding', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/js/onboarding.js', array('jquery'), SOFTACULOUS_PRO_VERSION, false);
		wp_localize_script('softaculous-pro-script-onboarding', 'softwp_onboarding_lang', $softwp_onboarding_lang);
		
		wp_enqueue_style( 'softaculous-pro-style-onboarding', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/css/onboarding.css', [], SOFTACULOUS_PRO_VERSION, 'all' );
		
		wp_enqueue_style( 'softaculous-pro-style-font-awesome', SOFTACULOUS_PRO_PLUGIN_URL . '/assets/font-awesome/css/all.min.css', [], SOFTACULOUS_PRO_VERSION, 'all' );
	}
}

function spro_get_features_list(){
	
    $features_list = array(
        
		"seo" => array(
		"name" => __('Increase Website Traffic (SEO)','softaculous-pro'),
		"info" => __("Improve your site's ranking on search engines","softaculous-pro"),
		"icon" => 'dashicons dashicons-chart-bar',
		"plugin"=> array(
			"siteseo" => array(
				"plugin_name" => __("SiteSEO – One Click SEO for WordPress","softaculous-pro"),
				"plugin_url"=> "https://siteseo.io/",
				'plugin_init' => 'siteseo/siteseo.php',
				'plugin_download_url' => softaculous_pro_api_url(0, 'siteseo').'files/versions/latest-stable-free.zip',
				'plugin_init_pro' => 'siteseo-pro/siteseo-pro.php',
				'plugin_download_url_pro' => softaculous_pro_api_url(0, 'siteseo').'download.php',
				'plugin_desc' => __('Boost your website\'s search rankings today with the most powerful WordPress SEO plugin. Its lightweight, optimized, and delivers exceptional performance.', 'softaculous-pro'),
				'pro' => 1,
				'featured' => 1,
				'requires_php' => 7.2,
                ),
            )
        ),
		
        "speedycache" => array(
            "name" => __("Improve Page Speed","softaculous-pro"),
            "info" => __("Improve speed by cache, minify, compress", 'softaculous-pro'),
            "icon" => "fa-solid fa-gauge-high",
            "plugin"=> array(
                "speedycache" => array(
                    "plugin_name" => __("SpeedyCache – Cache, Optimization, Performance","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/speedycache/",
					'plugin_init' => 'speedycache/speedycache.php',
					'plugin_init_pro' => 'speedycache-pro/speedycache-pro.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'speedycache').'download.php',
					'plugin_desc' => __('SpeedyCache is an easy to use and powerful WordPress Cache Plugin, it helps you reduce page load time improving User Experience and boosting your Google PageSpeed.', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 7.3,
                ),
            )
        ),
		
        "backuply" => array(
            "name" => __("Schedule Backups","softaculous-pro"),
            "info" => __("Backup your site on local or remote servers","softaculous-pro"),
            "icon" => "fa-regular fa-file-zipper",
            "plugin"=> array(
                "backuply" => array(
                    "plugin_name" => __("Backuply – Backup, Restore, Migrate and Clone","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/backuply/",
					'plugin_init' => 'backuply/backuply.php',
					'plugin_init_pro' => 'backuply-pro/backuply-pro.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'backuply').'download.php',
					'plugin_desc' => __('Backuply is a WordPress backup plugin that helps you backup your WordPress website, saving you from loss of data because of server crashes, hacks, dodgy updates, or bad plugins.', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 5.5,
                ),
            )
        ),
        
		"sell_products" => array(
            "name" => __("Sell Products","softaculous-pro"),
            "info" => __("Sell physical or digital products","softaculous-pro"),
            "icon" => "fa-solid fa-tag",
            "plugin"=> array(
                "woocommerce" => array(
                    "plugin_name" => __("WooCommerce","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/woocommerce/",
					'plugin_init' => 'woocommerce/woocommerce.php',
                ),
            )
        ),
		
        "loginizer" => array(
            "name" => __("Limit Login Attempts","softaculous-pro"),
            "info" => __("Brute force protection, 2FA, login captcha", 'softaculous-pro'),
            "icon" => "fa-solid fa-user-lock",
            "plugin"=> array(
                "loginizer" => array(
                    "plugin_name" => __("Loginizer","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/loginizer/",
					'plugin_init' => 'loginizer/loginizer.php',
					'plugin_init_pro' => 'loginizer-security/loginizer-security.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'loginizer').'download.php',
					'plugin_desc' => __('Loginizer is a simple and effortless solution that takes care of all your security problems. It comes with default optimal configuration to protect your site from Brute Force attacks.', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 5.5,
                ),
            )
        ),
		
        "pagelayer" => array(
            "name" => __("Page Builder","softaculous-pro"),
            "info" => __("Page Builder, Drag and Drop website builder", 'softaculous-pro'),
            "icon" => "fa-solid fa-paintbrush",
            "plugin"=> array(
                "pagelayer" => array(
                    "plugin_name" => __("Pagelayer","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/pagelayer/",
					'plugin_init' => 'pagelayer/pagelayer.php',
					'plugin_init_pro' => 'pagelayer-pro/pagelayer-pro.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'pagelayer').'download.php',
					'plugin_desc' => __('Pagelayer is an awesome page builder that allows you to create and design your website instantly in the simplest way possible. Take control over your page content with the most advanced page builder plugin available.', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 5.5,
                ),
            )
        ),
		
        "gosmtp" => array(
            "name" => __("Send Email with SMTP","softaculous-pro"),
            "info" => __("Providers: Gmail, Outlook, AWS SES & more", 'softaculous-pro'),
            "icon" => "fa-solid fa-envelope-circle-check",
            "plugin"=> array(
                "gosmtp" => array(
                    "plugin_name" => __("GoSMTP – SMTP for WordPress","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/gosmtp/",
					'plugin_init' => 'gosmtp/gosmtp.php',
					'plugin_init_pro' => 'gosmtp-pro/gosmtp-pro.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'gosmtp').'download.php',
					'plugin_desc' => __('GoSMTP allows you to send emails from your WordPress over SMTP or many popular outgoing email service providers. Using these improves your email deliverability.', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 5.5,
                ),
            )
        ),
		
        "fileorganizer" => array(
            "name" => __("File Manager","softaculous-pro"),
            "info" => __("Manage files with drag & drop editor", 'softaculous-pro'),
            "icon" => "fa-regular fa-folder-open",
            "plugin"=> array(
                "fileorganizer" => array(
                    "plugin_name" => __("FileOrganizer – Manage WordPress and Website Files","softaculous-pro"),
                    "plugin_url"=> "https://wordpress.org/plugins/fileorganizer/",
					'plugin_init' => 'fileorganizer/fileorganizer.php',
					'plugin_init_pro' => 'fileorganizer-pro/fileorganizer-pro.php',
					'plugin_download_url_pro' => softaculous_pro_api_url(0, 'fileorganizer').'download.php',
					'plugin_desc' => __('FileOrganizer is a lightweight and easy-to-use file management plugin for WordPress. Organize and manage your WordPress files with FileOrganizer without any control panel or FTP access. ', 'softaculous-pro'),
					'pro' => 1,
					'featured' => 1,
					'requires_php' => 5.5,
                ),
            )
        ),
    );
	
	$features_list = apply_filters('softaculous_pro_features_list', $features_list);
	
	return $features_list;
}


function softaculous_pro_ajax_output($data){
	
	echo json_encode($data);
	
	wp_die();
	
}

function softaculous_pro_ajax_output_xmlwrap($data){
	
	echo '<softaculous-pro-xmlwrap>'.json_encode($data).'</softaculous-pro-xmlwrap>';
	
	wp_die();
}

function softaculous_pro_import_template($slug, $items = array()){
	global $pl_error;

	$data = [];
	
	$destination = popularfx_templates_dir(false).'/'.$slug;
	
	include_once(PAGELAYER_DIR.'/main/import.php');
	
	// Our function needs to efficiently replace the variables
	$GLOBALS['softaculous_pro_template_import_slug'] = $slug;	
	add_filter('pagelayer_start_insert_content', 'softaculous_pro_pagelayer_start_insert_content', 10);
	
	// Now import the template
	if(!pagelayer_import_theme($slug, $destination, $items)){
		$data['error']['import_err'] = __('Could not import the template !', 'softaculous-pro');
		$data['error'] = array_merge($data['error'], $pl_error);
		return $data;
	}
	
	// Save the name of the slug
	set_theme_mod('popularfx_template', $slug);
	
	// onboarding done
	update_option('softaculous_pro_onboarding_done', time());
	
	// Set default left menu folded
	//set_user_setting('mfold', 'f');
	
	$data['done'] = 1;
	
	return $data;
	
}

// Download the template
function softaculous_pro_download_template($slug){
	
	global $softaculous_pro, $pl_error;	

	set_time_limit(300);
	
	$data = [];

	// Now lets download the templates
	if(!function_exists( 'download_url' ) ) {
		require_once ABSPATH . 'wp-admin/includes/file.php';
	}
	
	$spro_setup_info = get_option('softaculous_pro_setup_info');
	
	$url = softaculous_pro_pfx_api_url().'/givetemplate.php?slug='.$spro_setup_info['theme_slug'].'&license='.@$softaculous_pro['license']['license'].'&url='.site_url();
	//echo $url;
	
	$popular_fx_dir = popularfx_templates_dir(false);
	$destination = $popular_fx_dir.'/'.$slug;

	// Check if FTP is required
	ob_start();
	$credentials = request_filesystem_credentials('');
	ob_end_clean();

	if(false === $credentials || !WP_Filesystem($credentials)){
		$data['error']['download'] = __('Theme template can only be uploaded using FTP !', 'softaculous-pro');
		return $data;
	}
	
	global $wp_filesystem;
	
	// For FTP have to use relative paths
	if(is_array($credentials)){
		$abspath_relative = $wp_filesystem->find_folder(ABSPATH);
		$replacer = str_replace($abspath_relative, '', ABSPATH);
		if($replacer !== ABSPATH){
			$popular_fx_dir = str_replace($replacer, '', $popular_fx_dir);
			$destination = str_replace($replacer, '', $destination);
		}
	}

	$tmp_file = download_url($url);
	//echo filesize($tmp_file);
	//var_dump($tmp_file);
	
	// Error downloading
	if(is_wp_error($tmp_file) || filesize($tmp_file) < 1){
		if(!empty($tmp_file->errors)){			
			$data['error']['download_err'] = __('Could not download the theme !', 'softaculous-pro').var_export($tmp_file->errors, true);
			return $data;
		}
	}
	
	$wp_filesystem->mkdir($popular_fx_dir);
	$wp_filesystem->mkdir($destination);
	//echo $destination;

	$ret = unzip_file($tmp_file, $destination);
	//r_print($ret);
	
	// Try to delete
	@unlink($tmp_file);
	
	// Error downloading
	if(is_wp_error($ret) || !file_exists($destination.'/style.css')){
		if(!empty($ret->errors)){
			$data['error']['download'] = __('Could not extract the template !', 'softaculous-pro').var_export($ret->errors, true);
			return $data;
		}
	}

	return $data;

}

// Get list of templates
function softaculous_pro_get_templates_list(){
	
	$data = get_transient('softaculous_pro_templates');

	// Get any existing copy of our transient data
	if(false === $data){
	
		// Start checking for an update
		$send_for_check = array(
			'timeout' => 90,
			'user-agent' => 'WordPress'		
		);
		
		$raw_response = wp_remote_post( softaculous_pro_pfx_api_url().'templates.json', $send_for_check );
		//pagelayer_print($raw_response);die();
	
		// Is the response valid ?
		if ( !is_wp_error( $raw_response ) && ( $raw_response['response']['code'] == 200 ) ){		
			$data = json_decode($raw_response['body'], true);
		}
		//pagelayer_print($data);die();
	
		// Feed the updated data into the transient
		if(!empty($data['list']) && count($data['list']) > 10){
			set_transient('softaculous_pro_templates', $data, 2 * HOUR_IN_SECONDS);
		}
		
	}
	
	return $data;
	
}

// Get the template info from our servers
function softaculous_pro_onboarding_dismiss(){

	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	
	if(isset($_REQUEST['dismiss'])){
		update_option('softaculous_pro_onboarding_dismiss', time());
	}
	
	$data['done'] = 1;
	
	softaculous_pro_ajax_output($data);
	
}

// Get the template info from our servers
function softaculous_pro_ajax_template_info(){

	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	
	$data = [];
	
	if(isset($_REQUEST['slug'])){		
		$resp = wp_remote_get(softaculous_pro_pfx_api_url().'template-info.php?slug='.$_REQUEST['slug'], array('timeout' => 30));
	
		// Is the response valid ?
		if ( !is_wp_error( $resp ) && ( $resp['response']['code'] == 200 ) ){		
			$data = json_decode($resp['body'], true);
		}
	}
		
	$setup_info = get_option('softaculous_pro_setup_info');
	$setup_info = !empty($setup_info) ? $setup_info : array();
	$setup_info['theme_slug'] = $_REQUEST['slug'];

	update_option('softaculous_pro_setup_info',$setup_info);
	
	softaculous_pro_ajax_output($data);
	
}

// Start the installation of the template
function softaculous_pro_ajax_start_install_template(){
	
	global $softaculous_pro;
	
	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');

	set_time_limit(300);
	
	// Handling Access through FTP
	ob_start();
	// Check if FTP is required
	$have_credentials = request_filesystem_credentials('');

	if(false === $have_credentials){
		$form_html = ob_get_clean();
		$ftp_modal = '<div id="request-filesystem-credentials-dialog" class="notification-dialog-wrap request-filesystem-credentials-dialog">
		<div class="notification-dialog-background"></div>
		<div class="notification-dialog" role="dialog" aria-labelledby="request-filesystem-credentials-title" tabindex="0">
		<div class="request-filesystem-credentials-dialog-content">'. $form_html . '</div></div></div>';

		wp_send_json_error(['form' => $ftp_modal]);
	}

	ob_end_clean(); // Just in case there was any output till now it will be cleaned.

	$data = [];
	
	//pagelayer_print($_POST);die();
	$license = softaculous_pro_optPOST('softaculous_pro_license');
	
	// Check if its a valid license
	if(!empty($license)){
	
		$resp = wp_remote_get(softaculous_pro_api_url(1).'license.php?license='.$license.'&url='.rawurlencode(site_url()), array('timeout' => 30));
	
		if(is_array($resp)){
			$json = json_decode($resp['body'], true);
			//print_r($json);
		}else{
		
			$data['error']['resp_invalid'] = __('The response from the server was malformed. Please try again in sometime !', 'softaculous-pro').var_export($resp, true);
			softaculous_pro_ajax_output($data);
			
		}
	
		// Save the License
		if(empty($json['license'])){
		
			$data['error']['lic_invalid'] = __('The license key is invalid', 'softaculous-pro');
			softaculous_pro_ajax_output($data);
			
		}else{
			
			update_option('softaculous_pro_license', $json);
	
			// Load license
			spro_load_license();
			
		}
		
	}
	
	// Load templates
	$softaculous_pro['templates'] = softaculous_pro_get_templates_list();
	
	$slug = softaculous_pro_optPOST('theme');
	
	if(!defined('PAGELAYER_VERSION')){
		
		$res = spro_install_required_plugin('pagelayer', array('plugin_init' => 'pagelayer/pagelayer.php'));
		
		if(empty($res['success'])){
			$data['error']['pl_req'] = __('Pagelayer is required to use the templates !', 'softaculous-pro');
			softaculous_pro_ajax_output($data);
		}
	}
	
	if(!defined('PFX_VERSION')){
		
		$res = spro_install_required_plugin('popularfx-templates', array('plugin_init' => 'popularfx-templates/popularfx-templates.php', 'plugin_download_url' => softaculous_pro_api_url(0, 'popularfx').'update2.php?give=1'));
		
		if(empty($res['success'])){
			$data['error']['pl_req'] = __('PopularFX plugin is required to use the templates !', 'softaculous-pro');
			softaculous_pro_ajax_output($data);
		}
	}
	
	if(!function_exists('popularfx_templates_dir')){

		$res = spro_install_required_theme('popularfx');
		
		if(empty($res['success'])){
			$data['error']['pfx_req'] = __('PopularFX theme is required to use the templates !', 'softaculous-pro');
			softaculous_pro_ajax_output($data);
		}
		
	}
	
	if(empty($softaculous_pro['templates']['list'][$slug])){
		$data['error']['template_invalid'] = __('The template you submitted is invalid !', 'softaculous-pro');
		softaculous_pro_ajax_output($data);
	}
	
	$template = $softaculous_pro['templates']['list'][$slug];
	
	// Do we have the req PL version ?
	if(!empty($template['pl_ver']) && version_compare(PAGELAYER_VERSION, $template['pl_ver'], '<')){
		$data['error']['pl_ver'] = sprintf(__('Your Pagelayer version is %1$s while the template requires Pagelayer version higher than or equal to %2$s ', 'softaculous-pro'), PAGELAYER_VERSION, $template['pl_ver']);
		softaculous_pro_ajax_output($data);
	}
	
	// Do we have the req PL version ?
	if(version_compare(PAGELAYER_VERSION, '1.8.9', '<')){
		$data['error']['pl_ver'] = sprintf(__('Your Pagelayer version is %1$s while the onboarding requires Pagelayer version higher than or equal to 1.8.9', 'softaculous-pro'), PAGELAYER_VERSION);
		softaculous_pro_ajax_output($data);
	}
	
	// Do we have the req PFX Plugin version ?
	if(!empty($template['pfx_ver']) && version_compare(PFX_VERSION, $template['pfx_ver'], '<')){
		$data['error']['pfx_ver'] = sprintf(__('Your PopularFX Plugin version is %1$s while the template requires PopularFX version higher than or equal to %2$s', 'softaculous-pro'), PFX_VERSION, $template['pfx_ver']);
		softaculous_pro_ajax_output($data);
	}
	
	// Is it a pro template ?
	if($template['type'] > 1 && empty($softaculous_pro['license']['active'])){
		$data['error']['template_pro'] = sprintf(__('The selected template is a Pro template and you have a free or expired license. Please enter your license key %1$shere%2$s.', 'softaculous-pro'), 
			'<a href="'.admin_url('admin.php?page=assistant&act=license').'" target="_blank" style="color:blue;">',
			'</a>'
			);
		softaculous_pro_ajax_output($data);
	}
	
	$do_we_have_pro = defined('PAGELAYER_PREMIUM');
	
	// Do we need to install Pagelayer or Pagelayer PRO ?
	if(!function_exists('pagelayer_theme_import_notices') || (empty($do_we_have_pro) && $template['type'] > 1)){
		if($template['type'] > 1){
			$download_url = SOFTACULOUS_PRO_PAGELAYER_API.'download.php?version=latest&license='.$softaculous_pro['license']['license'].'&url='.rawurlencode(site_url());
			$installed = spro_install_required_plugin('pagelayer-pro', array('plugin_init' => 'pagelayer-pro/pagelayer-pro.php', 'plugin_download_url' => $download_url));
		}else{
			$installed = spro_install_required_plugin('pagelayer', array('plugin_init' => 'pagelayer/pagelayer.php'));
		}
		
		// Did we fail to install ?
		if(is_wp_error($installed) || empty($installed)){
			$install_url = admin_url('admin.php?page=softaculous_pro_install_pagelayer&license=').@$softaculous_pro['license']['license'];
			$data['error']['pagelayer'] = sprintf(__('There was an error in installing Pagelayer which is required by this template. Please install Pagelayer manually by clicking %1$shere%2$s and then install the template !', 'softaculous-pro'), '<a href="%1$s" target="_blank">'.$install_url, '</a>');
			if(!empty($installed->errors)){
				$data['error']['pagelayer_logs'] = var_export($installed->errors, true);
			}
			softaculous_pro_ajax_output_xmlwrap($data);
		}
		
	}
	
	// Lets notify to download
	// $data['download'] = 1;
	$data['sel_plugin'] = 1;
	
	softaculous_pro_ajax_output_xmlwrap($data);
	
}

function softaculous_pro_ajax_selected_plugin (){
    
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
    
	if ( ! current_user_can( 'edit_posts' ) ) {    
        wp_send_json_error();
    }
	
    $results = array();
    $options = get_option('softaculous_pro_setup_info');
    $sel_features = $options['features'];
    if(!empty($sel_features)){
        $feature_list = spro_get_features_list();
        foreach($feature_list as $slug => $features){
            if (in_array($slug, $sel_features)) {
                foreach($features['plugin'] as $plugin_slug => $plugin_data){
					$res = spro_install_required_plugin($plugin_slug, $plugin_data);
					$results[] = array(
						'plugin_slug' => $plugin_slug,
						'status' => $res,
					);
                }
            }
        }
        foreach ($results as $item) {
            if (isset($item['status']['error'])) {
                $data['failed_plugin'][$item['plugin_slug']] = $item['status']['error'];
            }
        }
        $data['download'] = 1;
        softaculous_pro_ajax_output($data);
    }
}

// Download template
function softaculous_pro_ajax_download_template(){
	
	global $softaculous_pro;
	
	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	
	$slug = softaculous_pro_optPOST('theme');
	
	// Do the download
	$data = softaculous_pro_download_template($slug);
	
	// Any error ?
	if(!empty($data['error'])){
		softaculous_pro_ajax_output($data);
	}
	
	// Lets import then
	$data['import'] = 1;
	
	softaculous_pro_ajax_output($data);
	
}

// Import template
function softaculous_pro_ajax_import_template(){ 
	
	global $softaculous_pro, $pl_error;

	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	
	$slug = softaculous_pro_optPOST('theme');
	$to_import = softaculous_pro_optPOST('to_import');
	$_POST['set_home_page'] = 1;
	
	if(!empty($to_import)){
		$to_import[] = 'blog';
		$items = ['page' => $to_import];
	}else{
		$items = [];
	}
	
	// Import the template
	$data = softaculous_pro_import_template($slug, $items);
	
	softaculous_pro_ajax_output($data);
	
}

function softaculous_pro_save_setup_info(){
	// Some AJAX security
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	
	$step = $_POST['step'];
	$post_data = wp_unslash($_POST['data']);
	$setup_info = get_option('softaculous_pro_setup_info');
	
	$setup_info = !empty($setup_info) ? $setup_info : array();

	if($step === 'type' && !empty($post_data) ){
		$setup_info['type'] = strtolower(str_replace(" ", "", $post_data));
	}
	
	if($step === 'title' && !empty($post_data)){
		update_option('blogname', $post_data);
	}
	
	if($step === 'features' && !empty($post_data)){
		$setup_info['features'] = $post_data;
	}
	
	$steps = array( 'type', 'title', 'features', 'import');
	update_option('softaculous_pro_setup_info', $setup_info);
}

function softaculous_pro_get_options(){
	check_ajax_referer('softaculous_pro_ajax', 'softaculous_pro_nonce');
	$options = get_option('softaculous_pro_setup_info');
	wp_send_json($options);
}

function spro_install_required_plugin($slug, $plugin, $pro = 0){
	
	require_once ABSPATH . 'wp-admin/includes/plugin.php';
	require_once ABSPATH . 'wp-admin/includes/update.php';	
	include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
	include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
	$res = array();
	
	try{
		if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin['plugin_init'] ) && is_plugin_inactive( $plugin['plugin_init'] ) ) {
			activate_plugin($plugin['plugin_init']);
			$res['success'] = __("Plugin activated successfully.", 'softaculous-pro');
		}
		elseif ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin['plugin_init'] ) ){
			
			if (!empty($plugin['requires_php']) && version_compare(PHP_VERSION, $plugin['requires_php'], '<')) {
				throw new Exception(sprintf(__('Plugin installation failed. %1$s requires PHP version %2$s or higher. Your PHP version is %3$s.', 'softaculous-pro'),
					$plugin['plugin_name'],
					$plugin->requires_php,
					PHP_VERSION
				));
			}
			
			if(!empty($plugin['plugin_download_url'])){
				$download_url = $plugin['plugin_download_url'];
			}else{
				$api = plugins_api(
					'plugin_information',
					array(
							'slug'   => sanitize_key( wp_unslash( $slug ) ),
							'fields' => array(
								'sections' => false,
							),
						)
					);
				$download_url = $api->download_link;
			}
			
			$skin = new WP_Ajax_Upgrader_Skin();
			$upgrader = new Plugin_Upgrader( $skin );
			$result   = $upgrader->install($download_url);
				
			if ( is_wp_error($result) ) {
				throw new Exception(sprintf(__("Plugin installation failed. %1$s", 'softaculous-pro'), $result->get_error_message()));
			}
			elseif ( is_wp_error( $skin->result ) ) {
				throw new Exception(sprintf(__("Plugin installation failed. %1$s", 'softaculous-pro'), $skin->result->get_error_message()));
			} 
			elseif ( $skin->get_errors()->has_errors() ) {
				throw new Exception(sprintf(__("Plugin installation failed. %1$s", 'softaculous-pro'), $skin->get_error_messages()));
			} else {
				activate_plugin($plugin['plugin_init']);
				$res['success'] = __("Plugin installed and activated successfully.", 'softaculous-pro');
			}
		}else{
			$res['success'] = __("Plugin already installed.", 'softaculous-pro');
		}
	}
	catch( Exception $e){
		$res['error']  = $e->getMessage();
	}
	
	// Do we need to install the pro plugin as well ?
	if(empty($pro)){
		if(!empty($plugin['pro']) && !empty($plugin['plugin_download_url_pro'])){
			$plugin['plugin_download_url'] = softaculous_pro_add_params($plugin['plugin_download_url_pro']);
			$plugin['plugin_init'] = $plugin['plugin_init_pro'];
			$res['pro'] = spro_install_required_plugin($slug, $plugin, 1);
		}
	}
	
	return $res;
}

function spro_install_required_theme($slug, $theme = array()){
	
	$res = [];
	
	try {

		// Check if user is an admin and has appropriate permissions
		if(!current_user_can('install_themes')){
			throw new Exception(__("You do not have enough permissions to install theme", 'softaculous-pro'));
			return [];
		}

		if(!empty($theme['theme_download_url'])){
			$download_url = $theme['theme_download_url'];
		}else{
			$api = themes_api(
				'theme_information',
				array(
						'slug'   => sanitize_key( wp_unslash( $slug ) ),
						'fields' => array(
							'sections' => false,
							'downloadlink' => true,
						),
					)
				);
			$download_url = $api->download_link;
		}

		$theme_name = $slug;

		if(wp_get_theme($theme_name)->exists()){
			
			// Activate the theme
			switch_theme($theme_name);
			$res['success'] = __("Theme activated successfully.", 'softaculous-pro');
			
			return $res;
		}

		// Use WP Filesystem API to manage theme installation
		if(!function_exists('WP_Filesystem')){
			require_once(ABSPATH . 'wp-admin/includes/file.php');
		}

		// Check if FTP is required
		ob_start();
		$credentials = request_filesystem_credentials('');
		ob_end_clean();

		if(false === $credentials || !WP_Filesystem($credentials)){
			$res['error'] = __('The filesystem could not write files to the server!', 'softaculous-pro');
			return $res;
		}

		global $wp_filesystem;

		// The directory where themes are installed
		$theme_dir = $wp_filesystem->wp_themes_dir();

		// Download the theme zip file
		$theme_zip = download_url($download_url);

		// Check for errors during download
		if(is_wp_error($theme_zip)){
			throw new Exception(sprintf(__('Error downloading theme: %1$s', 'softaculous-pro'), $theme_zip->get_error_message()));
		}

		// Unzip the downloaded theme file
		$unzip_result = unzip_file($theme_zip, $theme_dir);

		// Check for errors during unzip
		if(is_wp_error($unzip_result)){
			throw new Exception(sprintf(__('Error unzipping theme: ', 'softaculous-pro'), $unzip_result->get_error_message()));
		}

		// Delete the temporary zip file
		unlink($theme_zip);

		// Activate the theme after installation
		switch_theme($theme_name);
	}catch(\Exception $e){
		$res['error'] = __('Theme installation failed ', 'softaculous-pro') . $e->getMessage();
		return $res;
	}

	$res['success'] = __("Theme installed and activated successfully.", 'softaculous-pro');

	return $res;
}

// This is to replace the image variables for the template URL
function softaculous_pro_pagelayer_start_insert_content($post){
	
	$url = popularfx_templates_dir_url().'/'.$GLOBALS['softaculous_pro_template_import_slug'].'/';
	
	$replacers['{{theme_url}}/images/'] = $url.'images/';
	$replacers['{{theme_url}}'] = $url;
	$replacers['{{theme_images}}'] = $url.'images/';
	$replacers['{{themes_dir}}'] = dirname(get_stylesheet_directory_uri());
	
	foreach($replacers as $key => $val){
		$post['post_content'] = str_replace($key, $val, $post['post_content']);
	}
		
	return $post;
	
}

if(!function_exists('softaculous_pro_templates')){

// The Templates Page
function softaculous_pro_templates(){

	global $softaculous_pro, $pl_error, $spro_setup_info;
	
	$softaculous_pro['templates'] = softaculous_pro_get_templates_list();

	$spro_setup_info = get_option('softaculous_pro_setup_info');
	
	if(isset($_REQUEST['install'])){
		check_admin_referer('softaculous-pro-template');
	}

	// Is there a license key ?
	if(isset($_POST['install'])){
		
		$done = 1;
		
	}
	
	softaculous_pro_templates_T();
	
}

// The License Page - THEME
function softaculous_pro_templates_T(){
	
	global $softaculous_pro, $pagelayer, $pl_error, $spro_setup_info;
	
	// Any errors ?
	if(!empty($pl_error)){
		pagelayer_report_error($pl_error);echo '<br />';
	}
	
?>
<div id="softaculous_pro_theme_title">
	<h1 style="text-align:center;"><?php _e('Choose a design', 'softaculous-pro'); ?></h1><br /><br />
</div>
<div id="softaculous_pro_search" class="softaculous-pro-row">
	<div class="softaculous-pro-search">
		<input type="text" class="softaculous-pro-search-field" placeholder="<?php _e('Search for theme', 'softaculous-pro'); ?>" />    
		<div id="softaculous-pro-suggestion"></div>
	</div>
    <div class="softaculous-pro-dropdown softaculous-pro-categories">
		<div class="softaculous-pro-current-cat"><?php _e('All', 'softaculous-pro'); ?></div><span class="dashicons dashicons-arrow-down-alt2"></span>
		<div class="softaculous-pro-dropdown-content"><div class="softaculous-pro-cat-holder softaculous-pro-row" style="justify-content:flex-start;"></div></div>
	</div>
</div>
<div class="softaculous-pro-page" id="softaculous-pro-templates-holder">
	<div id="softaculous-pro-pagination"></div>
	<div id="softaculous-pro-templates" class="softaculous-pro-row" style="justify-content:flex-start"></div>
	<div id="softaculous-pro-single-template">
		<div style="margin-bottom: 20px; margin-top: 10px;  text-align: left;">
			<h1 style="display: inline-block;margin: 0px;vertical-align: middle;" id="softaculous-pro-template-name"></h1>
			<?php if (empty($softaculous_pro['branding']['rebranded'])): ?>
				<a href="" id="softaculous-pro-demo" class="button softaculous-pro-demo-btn" target="_blank"><?php _e('Demo', 'softaculous-pro'); ?></a>
			<?php endif; ?>
		</div>
		<div style="margin: 0px; vertical-align: top;" class="single-template-div">
			<div style="text-align: center;  position:relative; width:80%;">
				<div style="width: 100%; max-height: 500px; overflow: auto; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);" class="single-templates-content">
				<div class="loader-container" >
					<div class="loader" style="display:none"></div>
				</div>
					<img id="softaculous_pro_display_image" src="" width="100%" style="position:relative; z-index:2;">
				</div>
			</div>
			<div class="softaculous_pro_single_content">
				<h1 style="font-size:16px;"><?php _e('Select pages to import', 'softaculous-pro'); ?></h1><br />
				<div id="softaculous_pro_screenshots"></div>
			<div class="softaculous_pro_import_img_notice">
				<form id="softaculous-pro-import-form" method="post" enctype="multipart/form-data">
					<?php wp_nonce_field('softaculous-pro-template');?>
					<input name="theme" id="softaculous-pro-template-install" value="" type="hidden" />
					<input type="checkbox" name="download_imgs" id="download_imgs" value="1" checked/> <label for="download_imgs" class="spro-tool-tip" style="cursor:pointer;"><?php _e('Import stock images ?', 'softaculous-pro'); ?></label><br />
					<i>
						<?php _e('We try our best to use images that are free to use from legal perspectives. However, we are not liable for any copyright infringement for your site.', 'softaculous-pro'); ?>
					</i>
					<input name="install" value="1" type="hidden" />
				</form>
			</div>
			</div>
		</div>

		<div style="position:fixed; bottom: 15px; right: 20px; z-index: 10;">
			<div class="button button-softaculous-pro softaculous-pro-back"  style="display:none;"><?php _e('Go Back', 'softaculous-pro'); ?></div>&nbsp;
			<input name="import_theme" class="button button-softaculous-pro" id="spro_import_content" value="<?php _e('Import Theme Content', 'softaculous-pro'); ?>" type="button" onclick="softaculous_pro_modal('#SproTemplatesModal')" style="display:none;"/> &nbsp;
		</div>	
	
	</div>
</div>

<!-- The Modal -->
<div id="SproTemplatesModal" class="softaculous-pro-modal">

	<!-- Modal holder -->
	<div class="softaculous-pro-modal-holder">

		<!-- Modal header -->
		<div class="softaculous-pro-modal-header">
			<h1><?php _e('Import Theme Contents', 'softaculous-pro'); ?></h1> 
			<!-- <span class="softaculous-pro-modal-close">&times;</span> -->
		</div>
		<!-- Modal content -->
		<div class="softaculous-pro-modal-content">
			<div class="softaculous-pro-import">
				<div id="softaculous-pro-error-template"></div>
				<div id="softaculous-pro-progress-template">
					<img src="<?php echo esc_attr(SOFTACULOUS_PRO_PLUGIN_URL) .'assets/images/progress.svg';?>" width="20" /> <span id="softaculous-pro-progress-txt"></span>
				</div>
			</div>
			<div class="softaculous-pro-done" style="display: block;">
				<h3 style="margin-top: 0px;"><?php _e('Congratulations, the template was imported successfully !', 'softaculous-pro'); ?></h3>
				<?php _e('You can now customize the website as per your requirements with the help of Pagelayer or the Customizer.', 'softaculous-pro')
				.'<br /><br />
				<b>Note</b> : '.
				_e('We strongly recommend you change all images and media. We try our best to use images which are copyright free or are allowed under their licensing. However, we take no responsibilities for the same and recommend you change all media and images !', 'softaculous-pro'); ?>
			</div>
		</div>
		
		<!-- Modal footer -->
		<div class="softaculous-pro-modal-footer">
			<div class="softaculous-pro-done">
				<a class="button softaculous-pro-demo-btn" href="<?php echo site_url();?>" target="_blank"><?php _e('Visit Website', 'softaculous-pro'); ?></a> &nbsp;&nbsp;
				<a class="button softaculous-pro-demo-btn" href="<?php echo admin_url();?>" target="_blank"><?php _e('WordPress Dashboard', 'softaculous-pro'); ?></a> &nbsp;&nbsp;
				<a class="button softaculous-pro-demo-btn" href="<?php echo admin_url('admin.php?page=assistant');?>" target="_blank"><?php _e('Assistant', 'softaculous-pro'); ?></a>
			</div>
		</div>
	</div>

</div>

<script>

var softaculous_pro_setup_info = JSON.parse('<?php echo json_encode((!empty($spro_setup_info) ? $spro_setup_info : array())); ?>');

// Add to tabs override
jQuery(document).ready(function(){
	softaculous_pro_templates_fn(jQuery);
	if(softaculous_pro_setup_info && softaculous_pro_setup_info.type){
		softaculous_pro_setup_info.type = softaculous_pro_setup_info.type.replace("-", "");
		jQuery('#cat_button_'+softaculous_pro_setup_info.type).trigger("click");
	}
});

var softaculous_pro_ajax_nonce = '<?php echo wp_create_nonce('softaculous_pro_ajax');?>';
var softaculous_pro_ajax_url = '<?php echo admin_url( 'admin-ajax.php' );?>?&';
var softaculous_pro_demo = 'https://demos.popularfx.com/';

softaculous_pro_templates = <?php echo json_encode($softaculous_pro['templates']);?>;
var themes = softaculous_pro_templates['list'];
var categories = softaculous_pro_templates['categories'];
var mirror = '<?php echo softaculous_pro_sp_api_url("-1");?>files/themes/';

function softaculous_pro_update_cat_input(other_cat){
	jQuery('#cat_input').val(other_cat);
}

function softaculous_pro_templates_fn($){

// Back button handler
jQuery('.softaculous-pro-back').click(function(){
	softaculous_pro_show_themes(softaculous_pro_setup_info.type !== undefined ? softaculous_pro_setup_info.type.toLowerCase() : '');
	jQuery("#spro_import_content").hide();
	jQuery(".softaculous-pro-back").hide();
});

jQuery('.softaculous-pro-back-theme').click(function(){
	jQuery('#softaculous-pro-templates-holder').show();
	jQuery(this).parent().hide();
	jQuery('#SproTemplatesModal').hide();
});

jQuery('#cat_input').keyup(function() {
	
	var query = jQuery(this).val().toLowerCase();
	var cat_displayed = 0;
	
	jQuery(".category_btn").each(function( index ){
		var cslug = jQuery(this).find("input").attr("data-target");
		if(cslug.toLowerCase().includes(query)){
			jQuery(this).show();
			cat_displayed++;
		}else{
			jQuery(this).hide();
		}
		
		if(cat_displayed > 0){
			jQuery("#spro_no_cat_results").hide();
		}else{
			jQuery("#spro_no_cat_results").show();
		}
	});
	
});

// Fill the categories
var chtml = '<div class="softaculous-pro-md-4 softaculous-pro-cat" data-cat="">All</div>';
for(var x in categories){
	chtml += '<div class="softaculous-pro-md-4 softaculous-pro-cat" data-cat="'+x+'">'+categories[x]['en']+'</div>';
}

jQuery('.softaculous-pro-cat-holder').html(chtml);
jQuery('.softaculous-pro-cat-holder').find('.softaculous-pro-cat').click(function(){
	softaculous_pro_show_themes(jQuery(this).data('cat'));
});

jQuery('.softaculous-pro-categories-list').find('.category_btn').click(function(){
	var childEle = jQuery(this).children('input');
	var jEle_parent =  jQuery(this).parent().find(".active_category");
	var real_val = jQuery(this).children('input').val();
	var val = jQuery(this).children('input').val().toLowerCase();
	var inputSection = jQuery(".softaculous-pro-category-input");


	if (jQuery(this).hasClass("active_category")) {
		jQuery(this).removeClass("active_category");
		inputSection.find('input').val('')
		return;
	}
	
	jEle_parent.removeClass("active_category");
	jQuery(this).addClass("active_category");
	
	if(real_val){
		inputSection.find('input').val(real_val)
	}
	
	softaculous_pro_show_themes(val);
});

// Search Clear
jQuery('.softaculous-pro-sf-empty').click(function(){
	jQuery('.softaculous-pro-search-field').val('');
	softaculous_pro_show_themes();
});

// Search
jQuery('.softaculous-pro-search-field').on('keyup', function(e){
	softaculous_pro_show_themes('', jQuery(this).val());
});

// Sort themes
jQuery('.softaculous-pro-sortby').change(function(){
	softaculous_pro_show_themes(jQuery('.softaculous-pro-current-cat').data('cat'), jQuery('.softaculous-pro-search-field').val());
});

};

// Show the themes
function softaculous_pro_show_themes(cat, search, page){
	
	softaculous_pro_show_themes_loaded = 1;
	
	var sortby = 'latest';
	jQuery("#softaculous_pro_search").show();	
	jQuery("#softaculous_pro_theme_title").show();	
	jQuery("#softaculous-pro-suggestion").hide();	
	jQuery("#softaculous-pro-single-template").hide();
	jQuery("#softaculous-pro-pagination").show();
	jQuery("#softaculous-pro-templates").show();
	
	// Blank html
	jQuery('#softaculous-pro-templates').html('');
	jQuery('#softaculous-pro-pagination').html('');

	var search = search || "";
	var cat =   cat || softaculous_pro_setup_info.type || "";
	var cat = cat.replace("-", "");
	softaculous_pro_setup_info.type = cat;
	var cat = (categories[cat] === undefined && (cat && cat.length) > 0 ? 'others' : cat) || "" ;

	var num = 60;
	var page = page || 1;
	var start = num * (page - 1);
	var end = num + start;
	var i = 0;
	var cat_appender = categories[cat] === undefined ? 'Others' : categories[cat]['en']

	if(cat.length > 0){
		jQuery('.softaculous-pro-current-cat').html(cat_appender);
		jQuery('.softaculous-pro-current-cat').data('cat', cat);
	}else{
		jQuery('.softaculous-pro-current-cat').html('All');
		jQuery('.softaculous-pro-current-cat').data('cat', '');
	}
	
	var allowed_list = [];
	
	if(search.length > 0){
		search = search.toLowerCase();
		
		for(var x in softaculous_pro_templates['tags']){
			if(x.toLowerCase().indexOf(search) >= 0){
				allowed_list = allowed_list.concat(softaculous_pro_templates['tags'][x]);
			}
		}
	}
	
	if(allowed_list.length > 0){
		allowed_list = Array.from(new Set(allowed_list));
	}
	
	var themeids = [];
	var sorted = {};
	var rsorted = {};
	
	for(var x in themes){
		themeids.push(parseInt(themes[x].thid));
	}	
	
	if(sortby == "latest"){
		var datatheme = Object.values(themes);
		var rsorted_ids = themeids.sort().reverse();
		for(var x of rsorted_ids){
			for( var y in datatheme){
				if(datatheme[y].thid == x){
					rsorted[datatheme[y].slug] = datatheme[y];
				}
			}
		}
		themes = rsorted;
	
	}else if(sortby == "oldest"){
		var datatheme = Object.values(themes);
		var sorted_ids = themeids.sort();
		for(var x of sorted_ids){
			for( var y in datatheme){
				if(datatheme[y].thid == x){
					sorted[datatheme[y].slug] = datatheme[y];
				}
			}
		}
		
		themes = sorted;
		
	}else{
		themes = softaculous_pro_templates['list'];		
	}	
	
	for(var x in themes){
		
		// Is it same category
		if(cat.length > 0 && cat != themes[x].category){
			continue;
		}
		
		// Is it a searched item
		if(search.length > 0 && themes[x].name.toLowerCase().indexOf(search) === -1 && allowed_list.indexOf(themes[x].thid) === -1){
			continue;
		}
		
		if(i >= start && i < end){
			//console.log(x+' '+i+' '+start+' '+end);
			softaculous_pro_show_theme_tile(themes[x], x);
		}
		
		i++;
		
	}
	
	jQuery('.softaculous-pro-theme-details').click(function(){
		var jEle = jQuery(this);
		softaculous_pro_show_theme_details(jEle.attr('slug'));
	});
	
	var pages = Math.ceil(i/num);
	
	if(pages > 1){
		
		var html = '<ul class="pagination">';
		
		for(var p = 1; p <= pages; p++){
			html += '<li class="page-item '+(page == p ? 'active' : '')+'"><a class="page-link" href="#" data-cat="'+cat+'" data-search="'+search+'" data-page="'+p+'">'+p+'</a></li>';
		}
		
		html += '</ul>';
		
		jQuery('#softaculous-pro-pagination').html(html);
		
		jQuery('#softaculous-pro-pagination').find('.page-link').click(function(){
			var j = jQuery(this);
			softaculous_pro_show_themes(j.data('cat'), j.data('search'), j.data('page'));
		});
		
	}
	
}

function softaculous_pro_show_theme_tile(theme, x){
	var html = '<div class="softaculous-pro-md-4">'+
		'<div class="softaculous-pro-theme-details" slug="'+theme['slug']+'" thid="'+theme['thid']+'">'+
			'<div class="softaculous-pro-theme-screenshot">'+
				'<img src="'+mirror+'/'+theme['slug']+'/screenshot.jpg" loading="lazy" alt="" />'+
			'</div>'+
			'<div class="softaculous-pro-theme-name">'+theme['name']+'</div>'+
		'</div>'+
	'</div>';
	jQuery('#softaculous-pro-templates').append(html);
}

function softaculous_pro_strip_extension(str){
    return str.substr(0,str.lastIndexOf('.'));
}

// Show the theme details
function softaculous_pro_show_theme_details(slug){
	
	var theme = themes[slug];
	
	jQuery("#softaculous-pro-suggestion").hide();	
	jQuery("#softaculous_pro_search").hide();	
	jQuery("#softaculous_pro_theme_title").hide();	
	jQuery("#softaculous-pro-single-template").show();
	jQuery("#softaculous-pro-pagination").hide();
	jQuery("#softaculous-pro-templates").hide();
	
	// Set install value
	jQuery('#softaculous-pro-template-install').val(slug);
			
	// Set name
	jQuery("#softaculous-pro-template-name").html(theme['name']);
			
	// Demo URL
	jQuery("#softaculous-pro-demo").attr("href", softaculous_pro_demo+(theme['name'].replace(' ', '_')));
	
	// Blank screenshots
	jQuery("#softaculous_pro_screenshots").html('');
	
	// Is the license PRO ?
	if(theme['type'] >= 2){
		jQuery('#softaculous_pro_license_div').css('display', 'inline-block');
	}else{
		jQuery('#softaculous_pro_license_div').hide();
	}
	
	var url = mirror+'/'+theme['slug'];
	
	// Show home image
	jQuery("#softaculous_pro_display_image").attr("src", "");
	jQuery("#softaculous_pro_display_image").attr("src", url+'/screenshots/home.jpg');
	jQuery("#softaculous_pro_display_image").parent().scrollTop(0);
	
	// Make the call
	jQuery.ajax({
		url: softaculous_pro_ajax_url+'action=softaculous_pro_template_info',
		type: 'POST',
		data: {
			softaculous_pro_nonce: softaculous_pro_ajax_nonce,
			slug: slug
		},
		dataType: 'json',
		success:function(theme) {
			
			jQuery("#spro_import_single").addClass("hidden");
			
			var sc = '';
			// var test= '';
			// Show the screenshots
			for(var x in theme['screenshots']){
				var page_name = softaculous_pro_strip_extension(theme['screenshots'][x]);
				sc += '<div class="softaculous_pro_img_screen" page="'+x+'" page-name="'+page_name+'">'+
				'<div class="spro_page_selector"><input type="checkbox" checked="checked" class="checkbox" id="'+page_name+'">'+
				'<label for="'+page_name+'" class="softaculous_pro_img_name">'+page_name+'</label></div>'+
				'<a href="'+url+'/screenshots/'+theme['screenshots'][x] +'" class="softaculous_pro_img_views view-'+page_name+' dashicons dashicons-visibility"></a>'+
				'</div>';
				
			}
			
			jQuery("#softaculous_pro_screenshots").html(sc);
			jQuery("#spro_import_content").show();
			jQuery(".softaculous-pro-back").show();
			jQuery('.softaculous_pro_img_screen:first').children('a').addClass('spro_img_inview');


			jQuery("#softaculous_pro_screenshots").find('.softaculous_pro_img_views').click(function(e){
				e.preventDefault();
				var jEle = jQuery(this);
				jQuery("#softaculous_pro_display_image").hide();
				jQuery(".loader").show();
				
				if(jQuery('.softaculous_pro_img_screen .softaculous_pro_img_views').hasClass('spro_img_inview')){
					jQuery('.softaculous_pro_img_screen .softaculous_pro_img_views').removeClass('spro_img_inview');
				}
				
				var newImageSrc = jEle.attr("href");
				jQuery("#softaculous_pro_display_image").attr("src", newImageSrc);

				// Handle image load event
				jQuery("#softaculous_pro_display_image").on('load', function() {
					jQuery(".loader").hide(); // Hide loader
					jQuery(this).show(); // Show image
				});

				// In case the image is cached and loads immediately
				if (jQuery("#softaculous_pro_display_image")[0].complete) {
					jQuery(".loader").hide(); // Hide loader
					jQuery("#softaculous_pro_display_image").show(); // Show image
				}

				jQuery("#softaculous_pro_display_image").parent().scrollTop(0);
				jEle.addClass('spro_img_inview');
			});

			// need to refactor it its create multiple in html
			jQuery("#softaculous_pro_screenshots").find('.softaculous_pro_img_views').on('mouseenter',function(e){
				var imgUrl = jQuery(this).attr('href');
				if(!jQuery(this).attr('loaded')){
					jQuery('<img>').attr('src', imgUrl).on('load', function() {}).appendTo('body').css('display', 'none');
				}
				jQuery(this).attr('loaded',true);
			});

			jQuery("#softaculous_pro_screenshots").find('.spro_page_selector').click(function(event){
				var jEle = jQuery(this);
				jQuery("#softaculous_pro_display_image").hide();
				jQuery(".loader").show();

				var checkbox = jQuery(this).find('.checkbox');
				if (jQuery(event.target).is('.checkbox') || jQuery(event.target).is('.softaculous_pro_img_name')) {
					return;
				}
				jEle.siblings('.softaculous_pro_img_views').trigger('click');
				
				
			});
			 // Change event on the checkbox
			 jQuery("#softaculous_pro_screenshots").find('.checkbox').change(function() {
				var checked_div = jQuery(this).siblings('.softaculous_pro_img_name');

				if(jQuery('.softaculous_pro_img_screen .softaculous_pro_img_views').hasClass('spro_img_inview')){
					jQuery('.softaculous_pro_img_screen .softaculous_pro_img_views').removeClass('spro_img_inview');
				}
				var newImageSrc = jQuery(this).parent().siblings('.softaculous_pro_img_views').attr("href");

				jQuery(this).parent().siblings('.softaculous_pro_img_views').addClass('spro_img_inview');
				jQuery("#softaculous_pro_display_image").attr("src", newImageSrc);

				jQuery("#softaculous_pro_display_image").on('load', function() {
					jQuery(".loader").hide(); // Hide loader
					jQuery(this).show(); // Show image
				});

				if (jQuery(this).is(':checked')) {
					checked_div.addClass("softaculous_pro_img_selected");
				} else {
					checked_div.removeClass("softaculous_pro_img_selected");
				}
			});
			
		}
	});
	
}

function softaculous_pro_onboarding_dismiss(e){
	
	jQuery.ajax({
		type: 'post',
		url: soft_pro_obj.ajax_url,
		data: {
			action: 'softaculous_pro_onboarding_dismiss',
			dismiss: 1,
			softaculous_pro_nonce: softaculous_pro_ajax_nonce,
			data: [],
		},
		complete: function (response) {
			window.location = soft_pro_obj.admin_url+"admin.php?page=assistant";
		},
	});
	
}

</script>

<?php


}

}disable-comments.php000064400000002752151526435000010512 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

add_action('admin_init', function () {
    // Redirect any user trying to access comments page
    global $pagenow;
     
    if ($pagenow === 'edit-comments.php') {
        wp_safe_redirect(admin_url());
        exit;
    }
 
    // Disable support for comments and trackbacks in post types
    foreach (get_post_types() as $post_type) {
        if (post_type_supports($post_type, 'comments')) {
            remove_post_type_support($post_type, 'comments');
            remove_post_type_support($post_type, 'trackbacks');
        }
    }
});

// Return 0 comments
add_filter('the_comments', 'softaculous_pro_the_comments', 10, 1);
function softaculous_pro_the_comments( $comments ) {
	return array();
}

// Return 0 comments number
add_filter('get_comments_number', 'softaculous_pro_get_comments_number', 10, 1);
function softaculous_pro_get_comments_number( $comments_number ) {
	return 0;
}
 
// Close comments on the front-end
add_filter('comments_open', '__return_false', 20, 2);
add_filter('pings_open', '__return_false', 20, 2);
 
// Hide existing comments
add_filter('comments_array', '__return_empty_array', 10, 2);
 
// Remove comments page in menu
add_action('admin_menu', function () {
    remove_menu_page('edit-comments.php');
});
 
// Remove comments links from admin bar
add_action('add_admin_bar_menus', function () {
    if (is_admin_bar_showing()) {
        remove_action('admin_bar_menu', 'wp_admin_bar_comments_menu', 60);
    }
});bloat.php000064400000024224151526435070006372 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class Bloat{

	static function actions(){
		global $speedycache;
		
		// Add the filters / actions
		if(!empty($speedycache->bloat['disable_xmlrpc'])){
			add_filter('xmlrpc_enabled', '__return_null');
			add_filter('bloginfo_url', '\SpeedyCache\Bloat::xmlrpc_remove_pingback_url', 10000, 2);
			add_action('wp_loaded', '\SpeedyCache\Bloat::xmlrpc_disable');
		}
		
		// Disable DashIcons
		if(!empty($speedycache->bloat['disable_dashicons'])){
			add_action('wp_print_styles', '\SpeedyCache\Bloat::disable_dashicons');
		}
		
		if(!is_admin()){
			// Remove jQuery migrate
			if(!empty($speedycache->bloat['disable_jmigrate'])){
				add_action('wp_default_scripts', '\SpeedyCache\Bloat::remove_jquery_migrate');
			}
			
			// Remove Block CSS
			if(!empty($speedycache->bloat['disable_block_css'])){
				add_action('wp_enqueue_scripts', '\SpeedyCache\Bloat::disable_block_editor_css');
			}

			// Disable Cart Fragment
			if(!empty($speedycache->bloat['disable_cart_fragment'])){
				add_action('wp_enqueue_scripts', '\SpeedyCache\Bloat::disable_cart_fragment', 11);
			}
			
			// Disable WooCommerce Assets
			if(!empty($speedycache->bloat['disable_woo_assets'])){
				add_action('wp_enqueue_scripts', '\SpeedyCache\Bloat::disable_woocommerce_assets', 99);
			}
			
			// Disale RSS Feeds
			if(!empty($speedycache->bloat['disable_rss'])){
				add_action('do_feed_rdf', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				add_action('do_feed_rss', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				add_action('do_feed_rss2', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				add_action('do_feed_atom', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				add_action('do_feed_rss2_comments', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				add_action('do_feed_atom_comments', '\SpeedyCache\Bloat::disable_wp_feeds', 1);
				
				// Remove links
				remove_action( 'wp_head', 'feed_links_extra', 3 );
				remove_action( 'wp_head', 'feed_links', 2 );
			}
		}

		// Disable OEmbeds
		if(!empty($speedycache->bloat['disable_oembeds'])){
			add_action('init', '\SpeedyCache\Bloat::disable_oembeds');
		}
		
		if(!empty($speedycache->bloat['disable_gutenberg'])){
			add_filter('use_block_editor_for_post_type', '__return_false', 100);
			add_filter('after_setup_theme', '\SpeedyCache\Bloat::disable_gutenberg_hooks');
		}
		
		// Limit Post revisions
		if(!empty($speedycache->bloat['limit_post_revision'])){
			add_filter('wp_revisions_to_keep', '\SpeedyCache\Bloat::limit_post_revisions');
		}

		// Update Heartbeat
		if(!empty($speedycache->bloat['update_heartbeat'])){
			add_action('init', '\SpeedyCache\Bloat::disable_heartbeat');
			add_action('wp_enqueue_scripts', '\SpeedyCache\Bloat::disable_heartbeat');
			add_action('admin_enqueue_scripts', '\SpeedyCache\Bloat::disable_heartbeat');
			add_filter('heartbeat_settings', '\SpeedyCache\Bloat::change_heartbeat_interval', 100);
		}
	}

	// Disbale XML request
	static function xmlrpc_disable(){
		global $pagenow;

		// Is it xmlrpc.php ?
		if ($pagenow === 'xmlrpc.php'){	
			echo 'XML-RPC is disabled';
			exit();
		}	
	}
	
	// Disables the XML-RPC functionality
	static function xmlrpc_remove_pingback_url($output, $show) {

		if($show == 'pingback_url'){
			$output = '';
		}

		return $output;
	}
	
	// Disable Dashicons
	static function disable_dashicons(){
		if(!is_admin_bar_showing() && !is_customize_preview()){
			wp_dequeue_style('dashicons');
			wp_deregister_style('dashicons');
		}
	}
	
	// Remove jQuery Migrate
	static function remove_jquery_migrate($scripts){
		
		if(!is_admin() && isset($scripts->registered['jquery'])){
			$script = $scripts->registered['jquery'];

			if($script->deps){
				$script->deps = array_diff($script->deps, array('jquery-migrate'));
			}
		}
	}
	
	// Disable OEmbeds
	static function disable_oembeds(){
		// Remove oEmbed REST API endpoint
		remove_action('rest_api_init', 'wp_oembed_register_route');

		// Disable oEmbed auto-discovery links
		remove_action('wp_head', 'wp_oembed_add_discovery_links');

		// Disable oEmbed-specific JavaScript from the front-end and back-end
		remove_action('wp_head', 'wp_oembed_add_host_js');

		// Remove oEmbed provider fetch URL rewriting
		remove_filter('oembed_fetch_url', 'wp_oembed_rewrite_url');

		// Disable oEmbed in TinyMCE editor
		add_filter('tiny_mce_plugins', '\SpeedyCache\Bloat::disable_tiny_mce_oembed');
	}

	static function disable_tiny_mce_oembed($plugins){
		return array_diff($plugins, array('wpembed'));
	}

	// Remove Block Editor CSS
	static function disable_block_editor_css(){
		wp_dequeue_style('wp-block-library');
		wp_dequeue_style('wp-block-library-theme');
		wp_dequeue_style('wp-block-style');
	}
	
	// Updates the count of number of post revesions.
	static function limit_post_revisions($num){
		global $speedycache;
		
		if(!empty($speedycache->bloat['post_revision_count']) && $speedycache->bloat['post_revision_count'] === 'disable'){
			$num = 0;
		} elseif(!empty($speedycache->bloat['post_revision_count']) && is_numeric($speedycache->bloat['post_revision_count'])){
			$num = intval($speedycache->bloat['post_revision_count']);
		}

		return $num;
	}
	
	// Updating the Heartbeat interval.
	static function change_heartbeat_interval($settings){
		global $speedycache;

		if(!empty($speedycache->bloat['heartbeat_frequency'])){
			$settings['interval'] = $speedycache->bloat['heartbeat_frequency'];
			$settings['minimalInterval'] = $speedycache->bloat['heartbeat_frequency'];
		}

		return $settings;
	}
	
	static function disable_cart_fragment(){
		if(function_exists('is_woocommerce')){
			if(!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()){
				wp_dequeue_script('wc-cart-fragments');
			}
		}
	}
	
	static function disable_woocommerce_assets(){
		if(!class_exists('WooCommerce')){
			return;
		}
		
		if(!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()){
			// Disable WooCommerce stylesheets
			wp_dequeue_style('woocommerce-general');
			wp_dequeue_style('woocommerce-layout');
			wp_dequeue_style('woocommerce-smallscreen');
			wp_dequeue_style('woocommerce_frontend_styles');
			wp_dequeue_style('woocommerce_fancybox_styles');
			wp_dequeue_style('woocommerce_chosen_styles');
			wp_dequeue_style('woocommerce_prettyPhoto_css');

			// Disable WooCommerce scripts
			wp_dequeue_script('wc_price_slider');
			wp_dequeue_script('wc-single-product');
			wp_dequeue_script('wc-add-to-cart');
			wp_dequeue_script('wc-checkout');
			wp_dequeue_script('wc-add-to-cart-variation');
			wp_dequeue_script('wc-single-product');
			wp_dequeue_script('wc-cart');
			wp_dequeue_script('wc-chosen');
			wp_dequeue_script('woocommerce');
			wp_dequeue_script('prettyPhoto');
			wp_dequeue_script('prettyPhoto-init');
			wp_dequeue_script('jquery-blockui');
			wp_dequeue_script('jquery-placeholder');
			wp_dequeue_script('fancybox');
			wp_dequeue_script('jqueryui');
		}
	}
	
	static function disable_wp_feeds(){
		 wp_die(sprintf(esc_html__('No feed available, please visit our %1$shomepage%2$s!'),
            ' <a href="' . esc_url( home_url( '/' ) ) . '">',
            '</a>'));
	}
	
	static function disable_heartbeat(){
		global $speedycache, $pagenow;

		if(empty($speedycache->bloat['disable_heartbeat'])) {
			return;
		}

		$remove_heartbeat = false;

		switch($speedycache->bloat['disable_heartbeat']){
			case 'disable':
				$remove_heartbeat = true;
				break;
				
			case 'editor':
				if($pagenow != 'post.php' && $pagenow != 'post-new.php'){
					$remove_heartbeat = true;
				}
		}
		
		if(!empty($remove_heartbeat)){
			wp_deregister_script('heartbeat');
		
			//We have replaced heartbeat with an empty heartbeat to prevent any errors
			wp_enqueue_script('heartbeat', SPEEDYCACHE_PRO_URL . '/assets/js/heartbeat.js', null, SPEEDYCACHE_PRO_VERSION, true);
		}
	}

	// Disable Gutenberg
	static function disable_gutenberg_hooks(){
		remove_action('admin_menu', 'gutenberg_menu');
		remove_action('admin_init', 'gutenberg_redirect_demo');

		remove_filter('wp_refresh_nonces', 'gutenberg_add_rest_nonce_to_heartbeat_response_headers');
		remove_filter('get_edit_post_link', 'gutenberg_revisions_link_to_editor');
		remove_filter('wp_prepare_revision_for_js', 'gutenberg_revisions_restore');

		remove_action('rest_api_init', 'gutenberg_register_rest_routes');
		remove_action('rest_api_init', 'gutenberg_add_taxonomy_visibility_field');
		remove_filter('rest_request_after_callbacks', 'gutenberg_filter_oembed_result');
		remove_filter('registered_post_type', 'gutenberg_register_post_prepare_functions');

		remove_action('do_meta_boxes', 'gutenberg_meta_box_save', 1000);
		remove_action('submitpost_box', 'gutenberg_intercept_meta_box_render');
		remove_action('submitpage_box', 'gutenberg_intercept_meta_box_render');
		remove_action('edit_page_form', 'gutenberg_intercept_meta_box_render');
		remove_action('edit_form_advanced', 'gutenberg_intercept_meta_box_render');
		remove_filter('redirect_post_location', 'gutenberg_meta_box_save_redirect');
		remove_filter('filter_gutenberg_meta_boxes', 'gutenberg_filter_meta_boxes');

		remove_action('admin_notices', 'gutenberg_build_files_notice');
		remove_filter('body_class', 'gutenberg_add_responsive_body_class');
		remove_filter('admin_url', 'gutenberg_modify_add_new_button_url'); // old
		remove_action('admin_enqueue_scripts', 'gutenberg_check_if_classic_needs_warning_about_blocks');
		remove_filter('register_post_type_args', 'gutenberg_filter_post_type_labels');

		remove_action('admin_init', 'gutenberg_add_edit_link_filters');
		remove_action('admin_print_scripts-edit.php', 'gutenberg_replace_default_add_new_button');
		remove_filter('redirect_post_location', 'gutenberg_redirect_to_classic_editor_when_saving_posts');
		remove_filter('display_post_states', 'gutenberg_add_gutenberg_post_state');
		remove_action('edit_form_top', 'gutenberg_remember_classic_editor_when_saving_posts');
	}
}
googlefonts.php000064400000013112151526435070007611 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt');
}

class GoogleFonts{

	// Plucks out the google font urls from the content
	static function get($content){

		preg_match_all('/<link.*href=(["\'])(.*fonts\.googleapis\.com\/css.*?)\1/m', $content, $font_rels);

		//We just need the index 2
		if(empty($font_rels[2])){
			return $content;
		}
		
		$fonts = array();
		
		for($i = 0; $i < count($font_rels[2]); $i++){
			if(empty($font_rels[2][$i])){
				continue;
			}
		
			$fonts[md5($font_rels[2][$i])] = $font_rels[2][$i];
		}
		
		if(empty($fonts)){
			return;
		}

		self::fetch($fonts);
	}

	// Reads the font css and saves it to /speedycache/fonts/font-name/
	static function fetch($fonts){
		
		$html = '<!DOCTYPE html>
<html>
<body>
<a href="https://speedycache.com">SpeedyCache</a>
</body>
</html>';
		

		foreach($fonts as $font_name => $url){
			$url = esc_url($url);

			if(substr($url, 0, 2) === '//'){
				$url = 'https:' . $url;
			}

			$response = wp_remote_get($url, array('user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36'));
			
			if(is_wp_error($response) || !is_array($response)){
				continue;
			}
			
			$css = wp_remote_retrieve_body($response);
			
			if(is_wp_error($css) || empty($css)){
				continue;
			}
			
			if(!file_exists(speedycache_cache_path('fonts'))){
				@mkdir(speedycache_cache_path('fonts'));
			}
			
			if(!file_exists(speedycache_cache_path('fonts/index.html'))){
				file_put_contents(speedycache_cache_path('fonts/index.html'), $html);
			}

			if(!file_exists(speedycache_cache_path('fonts/').$font_name)){
				@mkdir(speedycache_cache_path('fonts/').$font_name);
			}
			
			if(!file_exists(speedycache_cache_path('fonts/').$font_name . '/index.html')){
				file_put_contents(speedycache_cache_path('fonts/').$font_name . '/index.html', $html);
			}

			preg_match_all('/url\((.*?)\)/m', $response['body'], $urls); // Get URL from the CSS we got

			if(empty($urls) || empty($urls[1])){
				continue;
			}
			
			foreach($urls[1] as $url){
				$file_name = basename($url);
				
				if(file_exists(speedycache_cache_path('fonts/') . $font_name . '/' . $file_name)){
					continue;
				}

				if(strpos($url, 'display=swap') === FALSE){
					$url_to_hit = add_query_arg(array('display' => 'swap'), $url);
				}

				$response = wp_remote_get($url_to_hit);

				if(is_wp_error($response) || !is_array($response)){
					continue;
				}
				
				$font = wp_remote_retrieve_body($response);

				if(is_wp_error($font) || empty($font)){
					continue;
				}

				file_put_contents(speedycache_cache_path('fonts/').$font_name.'/'.$file_name, $font); // Creating the font file
				$css = str_replace($url, SPEEDYCACHE_CACHE_URL .'/'. SPEEDYCACHE_SERVER_HOST . '/fonts/'. $font_name .'/'. $file_name, $css);
			}

			if(file_exists(speedycache_cache_path('fonts/').$font_name.'/'.$font_name . '.css')){
				return;
			}

			//If we need to add swap then either we failed to add display=swap to the url or it didnt return what we expected.
			if(strpos($css, 'swap') === FALSE){
				$css = preg_replace('/(^@font-face\s{)/m', "$1\n  font-display: swap;", $css);
			}
			
			file_put_contents(speedycache_cache_path('fonts/').$font_name.'/'.$font_name . '.css', $css);
		}
	}

	// Replaces font url to the local font url
	static function replace($content){
		
		$cache_dir = speedycache_cache_path();
		
		if(!is_dir($cache_dir . '/fonts')){
			@mkdir($cache_dir . '/fonts', 0755, true);
		}

		$fonts = array_diff(@scandir($cache_dir . 'fonts'), array('..', '.'));
		
		if(empty($fonts)){
			return $content;
		}

		// To remove any preload or dns-fetch or preconnect for google fonts
		preg_match_all('/<link(?:[^>]+)?href=(["\'])([^>]*?fonts\.(gstatic|googleapis)\.com.*?)\1.*?>/i', $content, $google_links, PREG_SET_ORDER);
			
		if(!empty($google_links)){
			foreach($google_links as $google_link){

				preg_match('/rel=(["\'])(.*?(preload|preconnect|dns-fetch).*?)\1/i', $google_link[2], $removeable_link);

				if(!empty($removeable_link)){
					$content = str_replace($google, '', $html);
				}
			}
		}
		
		/**
		  * Our Font css name is in md5(created from the font URL) and we dont have URL in this function to get
		  * all the google fonts url to replace the fonts .
		*/
		preg_match_all('/<link.*href=(["\'])(.*fonts\.googleapis\.com\/css.*?)\1/m', $content, $font_rels);
		
		if(empty($font_rels[2])){
			return $content;
		}
		
		foreach($font_rels[2] as $url){
			foreach($fonts as $font){

				if(in_array($font, array('.', '..'))){
					continue;
				}
				
				if(!file_exists($cache_dir . 'fonts/' . $font . '/' . $font . '.css')){
					continue;
				}
				
				$css_url = SPEEDYCACHE_CACHE_URL .'/'. SPEEDYCACHE_SERVER_HOST . '/fonts/' . $font . '/' . $font . '.css';
				
				if(md5($url) === $font){
					$content = preg_replace('/<link(.*)href=(["\'])(.*fonts\.googleapis\.com\/css.*?)\2/m', '<link$1 href="'.$css_url .'" ', $content);
				}
			}
		}
		
		return $content;
	}
	
	static function add_swap($content){	
		$content = str_replace('&#038;display=swap', '', $content);
		$content = str_replace('&display=swap', '', $content);

		// Add font-display=swap as a querty parameter to Google fonts
		$content = str_replace('googleapis.com/css?family', 'googleapis.com/css?display=swap&family', $content);
		
		return $content;
	}

}
commoncss.php000064400000007154151526435070007275 0ustar00<?php 

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt!');
}

class CommonCss{
	
	static function get_endpoint($is_unusedcss = false){
		global $speedycache;

		$endpoints = get_transient('speedycache_ccss_endpoint');

		$target_file = empty($is_unusedcss) ? 'index.php' : 'ucss.php';

		$mirror = 'https://s4.softaculous.com/a/speedycache/critical-css/' . $target_file;		
		$license = strpos($speedycache->license['license'], 'SPDFY') !== 0 ? '' : $speedycache->license['license'];

		if(empty($endpoints)){
			$res = wp_remote_get(SPEEDYCACHE_API.'license.php?license='.$license.'&url='.rawurlencode(site_url()));

			// Did we get a response ?
			if(!is_array($res)){
				return $mirror;
			}
			
			if(empty($res['body'])){
				return $mirror;
			}

			$body = json_decode($res['body'], true);

			if(empty($body['fast_mirrors'])){
				return $mirror;
			}
			
			$endpoints = $body['fast_mirrors'];
			
			if(empty($endpoints) || !is_array($endpoints)){
				return $mirror;
			}
		}
		
		$index = floor(rand(0, count($endpoints) - 1));

		if(empty($endpoints[$index])){
			return $mirror;
		}

		set_transient('speedycache_ccss_endpoint', $endpoints, 180);

		$mirror = str_replace('a/softaculous', 'a/speedycache/critical-css/'.$target_file, $endpoints[$index]);
		
		return $mirror;
		
	}
	
	static function schedule($schedule_name, $urls){

		$scheduled = self::get_schedule(array($schedule_name));
		$time = time();
		
		if(!empty($scheduled) && isset(end($scheduled)['time'])){
			// getting the last index to get the last scheduled event
			$time = end($scheduled)['time'] + 10;
		}
		
		$final_schd_time = $time;
	
		if(!wp_next_scheduled($schedule_name, array('urls' => $urls))){
			wp_schedule_single_event($final_schd_time, $schedule_name, array('urls' => $urls));
		}
	}
	
	// Returns an array of cron event "speedycache_unused_css"
	static function get_schedule($event_name){
		$cron = _get_cron_array();
		
		if(empty($cron)){
			return false;
		}
		
		$scheduled = array();
		
		foreach($cron as $key => $crn){
			foreach($crn as $e_key => $event){
				if(!in_array($e_key, $event_name)){
					continue;
				}

				$args = [];

				foreach($event as $evt){
					if(!empty($evt['args'][0])){
						$args = $evt['args'][0];
					}
				}
				
				array_push($scheduled, array('name' => get_the_title($args), 'time' => $key));
			}
		}
		
		return $scheduled;
	}
	
	// Adds the Critical CSS to the cache file
	static function update_cached($file, $css){
		global $speedycache;

		if(!file_exists($file)){
			return;
		}

		$content = file_get_contents($file);
		
		if(empty($content)){
			return;
		}
		
		$content = static::update_content($content, $css);

		// Updates the .html.gz file
		if(!empty($speedycache->options['gzip'])){
			self::update_gzip($file, $content);
		}
		
		// Updates the .html file
		file_put_contents($file, $content);
	}

	static function update_gzip($file, $content){
		
		$gz_file = str_replace('.html', '.html.gz', $file);
		
		if(file_exists($gz_file)){
			unlink($gz_file);
		}
		
		$content = gzencode($content, 6);
		
		if(!empty($content)){
			file_put_contents($gz_file, $content);
		}
	}
	
	static function log($log_name, $message, $url = '-'){
		$ccss_logs = get_option($log_name, []);
		
		if(count($ccss_logs) > 10){
			array_shift($ccss_logs);
		}
		
		$ccss_logs[$url] = array('time' => date('h:i:s'), 'message' => $message);
		update_option($log_name, $ccss_logs);
	}
	
	
}youtube.html000064400000004451151526435070007142 0ustar00<html>
<head>
	<style type="text/css">
body{background-color:#000;color:#fff;font:12px Roboto,Arial,sans-serif;height:100%;margin:0;overflow:hidden;padding:0;position:absolute;width:100%}
.y{background-position:center center;background-repeat:no-repeat;background-size:cover;height:100%;position:absolute;width:100%}
.yb{position:absolute;cursor:pointer;width:90px;height:60px;background-color:#333;box-shadow:0 0 30px rgba(0,0,0,0.6);z-index:1;opacity:.8;border-radius:6px}
.yb:before{content:"";border-style:solid;border-width:15px 0 15px 26px;border-color:transparent transparent transparent #fff}
.yb, .yb:before{position:absolute;top:50%;left:50%;transform:translate3d(-50%,-50%,0)}
.yb:hover{background-color:#ff0000;}
iframe{position:absolute;height:100%;width:100%;top:0;left:0;}
	</style>
	<script type="text/javascript">
var i=location.hash.match(/\#([^\?]+)/);
function img(){
	var q = window.innerWidth < 321 ? "mqdefault" : (window.innerWidth > 320 && window.innerWidth < 481 ? "hqdefault" : (window.innerWidth > 480 && window.innerWidth < 750 ? "sddefault" : "maxresdefault"));
	var img = document.createElement("IMG");
	img.setAttribute( "src", 'https://i.ytimg.com/vi/' + i[1] + '/' + q + '.webp');
	img.addEventListener('load', function(e){
		if(e.target.width == 120 && e.target.height == 90 && window.innerWidth > 320){
			e.target.setAttribute( 'src', 'https://i.ytimg.com/vi/' + i[1] + '/' + "hqdefault" + '.jpg');
		}
		document.getElementById("d").style['background-image'] = 'url(' + e.target.src + ')';
	});
	
	
	document.getElementById('d').addEventListener('click', function(){
		var start = window.location.hash.match(/[^a-zA-Z\d\s:](start\=\d+)/i);
		var hash = ["rel=0", "showinfo=0", "autoplay=1"];
		var ifrm = document.createElement("iframe");
		if(start){hash.push(start[1]);}
		ifrm.setAttribute("frameborder", "0");
		ifrm.setAttribute("allowfullscreen", "");
		ifrm.setAttribute("allow", "autoplay");
		ifrm.setAttribute( "src", "https://www.youtube.com/embed/"+ i[1] +"?" + hash.join("&"));
		this.innerHTML = "";
		this.appendChild(ifrm);
	});
};

window.addEventListener('resize', function(){img();});
window.addEventListener('load', function(){img();});


	</script>
</head>
<body>
	<div id="d" class="y">
		<div class="yb"></div>
	</div>
</body>
</html>cli.php000064400000003202151526435070006031 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

if(!defined('ABSPATH')){
    exit;
}

if(!defined('WP_CLI')){
    return;
}

class speedycache_cli extends \WP_CLI_Command{


	/**
	  * Purges/Cleares cache or minified files
	  * ## OPTIONS
	  * <type>
	  * : Purges cache or minified
	  * ---
	  * options:
	  *  - cache
	  *  - and minified
	  *
	  * ## EXAMPLES
	  * # Purge Cache
	  * $ wp speedycache purge cache
	  *
	  * # Purge cache and minfied
	  * $ wp speedycache purge cache and minified
	*/
	public function purge($args, $args_assoc){
		global $speedycache;

		if(!isset($speedycache)){
			WP_CLI::error('speedycache has not been defined!');
		}

		if(!function_exists('speedycache_delete_cache')){
			WP_CLI::error('speedycache_delete_cache() does not exist!');
		}

		if(empty($args[0]) || $args[0] !== 'cache'){
			self::wrong_usage();
		}
		
		if(empty($args[1]) || empty($args[2])){
			$this->delete_cache();
			return;
		}
		
		if($args[1] == 'and' && $args[2] == 'minified'){
			$this->delete_cache(true);
			return;
		}
	
		self::wrong_usage();
	}
	
	private function delete_cache($minified_too = false){
		if(function_exists('speedycache_delete_cache')){
			WP_CLI::error('Somethinng Went Wrong: Unable to delete cache');
		}

		WP_CLI::line('Clearing the ALL cache...');
		
		if(defined('SPEEDYCACHE_VERSION') && version_compare(SPEEDYCACHE_VERSION, '1.2.0', '>=')){
			$delete['minified'] = $minified_too;
			\SpeedyCache\Delete::run($delete);
		} else {
			speedycache_delete_cache($minified_too);
		}

		WP_CLI::success('The cache has been cleared!');
	}
}

WP_CLI::add_command('speedycache', 'speedycache_cli');metaboxpro.php000064400000003743151526435070007454 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt');
}

class MetaboxPro{

	static function html($content, $post_id){
		global $speedycache;
		
		if(empty($speedycache->options['critical_css'])){
			return '';
		}

		$post_meta = get_post_meta($post_id, 'speedycache_post_meta', true);

		$html = '<div class="speedycache-option-wrap">
	<div class="speedycache-option-info">
		<span class="speedycache-option-name">'.esc_html__('Disable CriticalCSS', 'speedycache').'</span>
	</div>
	<label for="speedycache-disable-critical-css" class="speedycache-custom-checkbox">
		<input type="checkbox" id="speedycache-disable-critical-css" name="speedycache_disable_critical_css" '. (!empty($post_meta['disable_critical_css']) ? ' checked' : ''). '/>
		<div class="speedycache-input-slider"></div>
	</label>
</div>

<h3>Critical CSS</h3>
<p>Create Crtical CSS for this page</p>
<button class="button" id="speedycache-generate-specific-cache">Generate CriticalCSS</button>
';

		return $html;

	}

	static function enqueue_scripts(){
		global $speedycache, $post;

		if(empty($speedycache->options['critical_css'])){
			return;
		}

		wp_enqueue_script('speedycache_metabox', SPEEDYCACHE_PRO_URL . '/assets/js/metabox.js', array('jquery'), SPEEDYCACHE_PRO_VERSION, true);
		
		wp_localize_script('speedycache_metabox', 'speedycache_metabox', array(
			'nonce' => wp_create_nonce('speedycache_nonce'),
			'post_id' => !empty($post->ID) ? $post->ID : '',
			'url' => admin_url('admin-ajax.php')
		));
	}
	
	// Filter to sets options to be saved for post meta
	static function options($options){
		global $speedycache;
		
		if(empty($options)){
			$options = [];
		}
		
		if(!is_array($options)){
			$options = [$options]; 
		}
		
		if(!empty($speedycache->options['critical_css'])){
			$options[] = 'disable_critical_css';
		}
		
		return $options;
	}
}
db.php000064400000003766151526435070005666 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class DB{

	static function clean($type){
		global $wpdb;

		if($type === 'transient_options'){
			$wpdb->query("DELETE FROM `$wpdb->options` WHERE option_name LIKE '%\_transient\_%' ;");
			wp_send_json(array('success' => true));
		}
		
		if($type === 'expired_transient'){
			$wpdb->query("DELETE FROM `$wpdb->options` WHERE option_name LIKE '_transient_timeout%' AND option_value < " . time());
			
			wp_send_json(array('success' => true));
		}
		
		if($type === 'trackback_pingback'){
			$wpdb->query("DELETE FROM `$wpdb->comments` WHERE comment_type = 'trackback' OR comment_type = 'pingback' ;");
			wp_send_json(array('success' => true));
		}
		
		if($type === 'trashed_spam_comments'){
			$wpdb->query("DELETE FROM `$wpdb->comments` WHERE comment_approved = 'spam' OR comment_approved = 'trash' ;");
			wp_send_json(array('success' => true));
		}
		
		if($type === 'trashed_contents'){
			$wpdb->query("DELETE FROM `$wpdb->posts` WHERE post_status = 'trash';");
			wp_send_json(array('success' => true));
		}
		
		if($type === 'post_revisions'){
			$wpdb->query("DELETE FROM `$wpdb->posts` WHERE post_type = 'revision';");
			wp_send_json(array('success' => true));
		}
		
		if($type === 'all_warnings'){
			$wpdb->query("DELETE FROM `$wpdb->posts` WHERE post_type = 'revision';");
			$wpdb->query("DELETE FROM `$wpdb->posts` WHERE post_status = 'trash';");
			$wpdb->query("DELETE FROM `$wpdb->comments` WHERE comment_approved = 'spam' OR comment_approved = 'trash' ;");
			$wpdb->query("DELETE FROM `$wpdb->comments` WHERE comment_type = 'trackback' OR comment_type = 'pingback' ;");
			$wpdb->query("DELETE FROM `$wpdb->options` WHERE option_name LIKE '%\_transient\_%' ;");
			$wpdb->query("DELETE FROM `$wpdb->options` WHERE option_name LIKE '_transient_timeout%' AND option_value < " . time());

			wp_send_json(array('success' => true));
		}
	}

}

renderblocking.php000064400000111221151526435070010253 0ustar00<?php

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class RenderBlocking {

	static function init($html){
		global $speedycache;
		
		$speedycache->render_blocking = array();
		$speedycache->render_blocking['except'] = '';
		$speedycache->render_blocking['tags'] = array();
		$speedycache->render_blocking['header_start_index'] = 0;
		$speedycache->render_blocking['js_tags_text'] = '';
		$speedycache->render_blocking['html'] = $html;
		
		self::set_header_start_index();
		self::set_tags();
		
		$speedycache->render_blocking['tags'] = self::reorder_tags($speedycache->render_blocking['tags']);
	}

	static function set_tags(){
		self::set_comments();
		self::set_js();
		self::set_css();
	}

	static function set_comments(){
		global $speedycache;
		
		$comment_tags = self::find_tags('<!--', '-->');

		self::set_except($comment_tags);

		foreach($comment_tags as $key => $value){
			if(preg_match("/\<\!--\s*\[if/i", $value['text'])){
				if(preg_match("/data-speedycache-render\=[\"\']false[\"\']/i", $value['text'])){
					continue;
				}

				array_push($speedycache->render_blocking['tags'], $value);
			}
		}
	}

	static function set_css(){
		global $speedycache;
		
		$style_tags = self::find_tags('<style', '</style>');

		foreach($style_tags as $key => $value){
			// <script>var xxx ={"id":"4", "html":"<style>\n\t\t\t.container{color:#CCCCCC;}\n\t\t<\/style>"};</script>
			if(!preg_match("/<\/script>/i", $value['text'])){
				array_push($speedycache->render_blocking['tags'], $value);
			}
		}

		$link_tags = self::find_tags('<link', '>');

		foreach($link_tags as $key => $value){
			if(preg_match("/href\s*\=/i", $value['text'])){
				if(preg_match("/rel\s*\=\s*[\'\"]\s*stylesheet\s*[\'\"]/i", $value['text'])){
					array_push($speedycache->render_blocking['tags'], $value);
				}
			}
		}
	}

	static function set_js(){
		global $speedycache;
		
		// Creating regex to exclude js from RenderBlocking
		if(!empty($speedycache->options['render_blocking_excludes'])){
			$exclude_script_list = array_map('preg_quote', $speedycache->options['render_blocking_excludes'], array_fill(0, count($speedycache->options['render_blocking_excludes']), '/'));
			$exclude_user_script = '/\b(?:' . implode('|', $exclude_script_list) . ')\b/';
		}
		
		$script_tag = self::find_tags('<script', '</script>');
		
		foreach($script_tag as $key => $value){
			
			if(self::exclude_scripts($value['text'])){
				continue;
			}
			
			// Excludes the user specified scripts
			if(!empty($exclude_user_script) && preg_match($exclude_user_script, $value['text'])){
				continue;
			}
			
			// Import map should always load at the same place as it is meant to be loaded before other scripts.
			if(preg_match("/importmap/i", $value['text'])){
			    continue;
			}

			//<script type='text/javascript' src='http://partner.googleadservices.com/gampad/google_service.js'></script>
			if(preg_match("/partner\.googleadservices\.com\/gampad\/google_service\.js/i", $value['text'])){
				continue;
			}

			// <script type='text/javascript'>
			// GS_googleAddAdSenseService("ca-pub-1059380037");
			// GS_googleEnableAllServices();
			// </script>
			if(preg_match("/<script[^\>]*>\s*GS_googleAddAdSenseService\([\"\'][^\"\']+[\"\']\)\;\s*GS_googleEnableAllServices\(\)\;\s*<\/script>/i", $value['text'])){
				continue;
			}

			// <script type='text/javascript'>
			// GA_googleAddSlot("ca-pub-1059380037", "viajablog-300-250");
			// </script>
			if(preg_match("/<script[^\>]*>\s*GA_googleAddSlot\([^\)]+\)\;\s*<\/script>/i", $value['text'])){
				continue;
			}

			// <script type='text/javascript'>
			// GA_googleFetchAds();
			// </script>
			if(preg_match("/<script[^\>]*>\s*GA_googleFetchAds\(\)\;\s*<\/script>/i", $value['text'])){
				continue;
			}

			// <script>
			//   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
			//   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
			//   m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
			//   })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

			//   ga('create', 'UA-9999-9', 'auto');
			//   ga('send', 'pageview');
			// </script>
			if(preg_match("/<script[^\>]*>\s*\(function\(i,s,o,g,r,a,m\)\{i\[\'GoogleAnalyticsObject\'\]/i", $value['text'])){
				if(preg_match("/ga\(\'send\',\s*\'pageview\'\)\;\s*<\/script>/i", $value['text'])){
					continue;
				}
			}

			// <script async src="https://www.googletagmanager.com/gtag/js?id=AW-123456789"></script>
			// <script>window.dataLayer=window.dataLayer||[];
			// function gtag(){
			// dataLayer.push(arguments);
			// }
			// gtag('js', new Date());
			// gtag('config', 'AW-123456789');</script>
			// <script type="text/javascript">
			// gtag('event', 'page_view', {
			// 'send_to': 'AW-123456789',
			// 'ecomm_pagetype': 'home'
			// });
			//</script>
			if(preg_match("/<script[^\>]+googletagmanager\.com\/gtag\/js[^\>]+>/i", $value['text'])){
				continue;
			}
			
			if(preg_match("/^<script>\s*window\.dataLayer\s*=\s*window\.dataLayer/i", $value['text']) && 
				preg_match("/gtag\([^\)]+\)\s*\;\s*<\/script>$/i", $value['text'])){
				continue;
			}

			/*
			<script id="bx24_form_inline" data-skip-moving="true">
				(function(w,d,u,b){w['Bitrix24FormObject']=b;w[b] = w[b] || function(){arguments[0].ref=u;
						(w[b].forms=w[b].forms||[]).push(arguments[0])};
						if(w[b]['forms']) return;
						var s=d.createElement('script');s.async=1;s.src=u+'?'+(1*new Date());
						var h=d.getElementsByTagName('script')[0];h.parentNode.insertBefore(s,h);
				})(window,document,'https://speedycache.bitrix24.com/bitrix/js/crm/form_loader.js','b24form');

				b24form({"id":"1","lang":"en","sec":"yesxbh","type":"inline"});
			</script>
			*/
			if(preg_match("/data-skip-moving\=[\"\']true[\"\']/i", $value['text'])){
				continue;
			}

			if(preg_match('/amzn_assoc_placement/i', $value['text'])){
				// <script>amzn_assoc_placement="adunit0";
				// amzn_assoc_search_bar="false";
				// amzn_assoc_tracking_id="3d0f1f-20";
				// amzn_assoc_ad_mode="search";
				// amzn_assoc_ad_type="smart";
				// amzn_assoc_marketplace="amazon";
				// amzn_assoc_region="US";
				// amzn_assoc_title="";
				// amzn_assoc_default_search_phrase="Spray Paint ";
				// amzn_assoc_default_category="All";
				// amzn_assoc_linkid="949bfb847147d654e679d4876a8e2b77";</script>
				continue;
			}
			
			//<script type="text/javascript">document.write("<div data-role=\"amazonjs\" data-asin=\"1234567890\" data-locale=\"JP\" data-tmpl=\"\" data-img-size=\"\" class=\"asin_1234567890_JP_ amazonjs_item\"><div class=\"amazonjs_indicator\"><span class=\"amazonjs_indicator_img\"></span><a class=\"amazonjs_indicator_title\" href=\"https://www.amazon.co.jp/%E5%B8%8%E5%AF%BF/dp/1234567890?SubscriptionId=AKIAIQGSXT2U7QVCQGHA&tag=hiyokoweb06-22&linkCode=xm2&camp=2025&creative=165953&creativeASIN=4335787\">希望難民ご一行様 ピースボートと「承認の共同体」幻想 (光文社新書)</a><span class=\"amazonjs_indicator_footer\"></span></div></div>")</script>
			if(preg_match("/^<script[^\>]*>\s*document.write\([\"\']\s*<div/i", $value['text'])){
				if(preg_match("/\s*<\/div>[\"\']\)\s*<\/script>$/i", $value['text'])){
					if(preg_match("/amazonjs/i", $value['text'])){
						continue;
					}
				}
			}

			if(preg_match('/reklamstore/i', $value['text'])){
				if(preg_match("/reklamstore_region_id/i", $value['text'])){
					continue;
				}else if(preg_match("/reklamstore\.com\/reklamstore\.js/i", $value['text'])){
					continue;
				}
			}

			//<script>document.write ('<iframe id="g2324_1" src="http://site.com/index.php?display_gallery_iframe&amp;gal_id=2324_1&amp;gal_type=2&amp;gal_cap=OFF&amp;gal_page=false"></iframe>');</script>
			if(preg_match("/document\.write\s*\(/i", $value['text'])){
				if(preg_match("/<iframe/i", $value['text'])){
					continue;
				}
			}

			//Yandex.Metrika counter
			if(preg_match("/mc\.yandex\.ru\/metrika\/watch\.js/i", $value['text'])){
				if(preg_match("/yandex_metrika_callbacks/i", $value['text'])){
					continue;
				}
			}

			//<script type="text/javascript" src="https://seal.thawte.com/getthawteseal?host_name=www.site.co.za&amp;size=S&amp;lang=en"></script>
			if(preg_match("/seal\.thawte\.com/i", $value['text'])){
				continue;
			}
			
			//<script type= "text/javascript">var RecaptchaOptions = {custom_translations : { instructions_visual : "This is my text:" }};</script>
			if(preg_match("/var\s+RecaptchaOptions\s*=\s*\{/i", $value['text'])){
				continue;
			}

			/*
			<script src='https://www.google.com/recaptcha/api.js?render=12356o4hLx1PTv7yszALlb5F_M&#038;ver=3.0'></script>
			<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=88a7E&amp;hl=en"></script>
			*/
			if(preg_match("/google\.com\/recaptcha\/api/i", $value['text'])){
				continue;
			}

			// <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
			// new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
			// j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
			// 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
			// })(window,document,'script','dataLayer','GTM-5NRFSPW');</script>
			if(preg_match("/googletagmanager\.com\/gtm\.js/i", $value['text']) && preg_match("/parentNode\.insertBefore/i", $value['text'])){
				continue;
			}

			//<script src="https://gist.github.com/name/89964fb23055f8d45f12345befd4d024.js"></script>
			if(preg_match("/gist\.github\.com\//i", $value['text'])){
				continue;
			}

			//<script async="asnyc" type="text/javascript" src="https://a-ssl.ligatus.com/?ids=11111&t=js&s=1"></script>
			if(preg_match("/a-ssl\.ligatus\.com/i", $value['text'])){
				continue;
			}

			//<script type="text/javascript" src="https://sealserver.trustwave.com/seal.js?style=invert&code=89999"></script>
			if(preg_match("/sealserver\.trustwave\.com\/seal\.js/i", $value['text'])){
				continue;
			}

			//<script language="javascript" src="//inviocare.us13.list-manage.com/generate-js/?u=f3707cdf398370b05&fid=4301&show=10" type="text/javascript"></script>
			if(preg_match("/inviocare\.us13\.list\-manage\.com\/generate\-js/i", $value['text'])){
				continue;
			}

			//<script type="text/javascript" src="https://form.jotform.co/jsform/60138856"></script>
			if(preg_match("/jotform[^\/]+\/jsform\/\d+/i", $value['text'])){
				continue;
			}

			//<script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/shell.js"></script>
			//<script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/v2.js"></script>
			if(preg_match("/js\.hsforms\.net\/forms\//i", $value['text'])){
				continue;
			}

			/*
			<script>hbspt.forms.create({
			portalId: 5102205,
			formId: "c11016e5-6a9a-4361-a358-a2ac92b8399e",
			shortcode: "wp"
			});</script>
			*/
			if(preg_match("/<script>\s*hbspt\.forms\.create\([^\)]+\)\;\s*<\/script>/i", $value['text'])){
				continue;
			}

			//<script type="application/json" class="wp-playlist-script">
			if(preg_match("/<script[^\>]+application\/json[^\>]+/i", $value['text'])){
				// if(preg_match("/<script[^\>]+wp-playlist-script[^\>]+/i", $value['text'])){
				// 	continue;
				// }

				continue;
			}

			//<script type='application/ld+json' class='yoast-schema-graph yoast-schema-graph--main'></script>
			if(preg_match("/<script[^\>]+application\/ld\+json[^\>]+>/i", $value['text'])){
				continue;
			}

			//<script id='tmpl-nf-field-input' type='text/template'>
			//<script type='text/html' class='av-video-tmpl'>
			if(preg_match("/<script[^\>]+text\/(template|html)[^\>]+/i", $value['text'])){
				continue;
			}

			//<script type="text/css" id="tmpl-tribe_customizer_css">
			if(preg_match("/<script[^\>]+text\/css[^\>]+/i", $value['text'])){
				continue;
			}

			// <script src='https://snapppt.com/widgets/widget_loader/979939cd-504c-4b59-9dcc-9e9f39dc1d09/grid.js' class='snapppt-widget'></script>
			if(preg_match("/snapppt\.com\/widgets\/widget_loader/i", $value['text'])){
				continue;
			}

			// <script src="/plugins/smart-cookie-kit/res/empty.js" data-blocked="http://maps.googleapis.com/maps/api/js" data-sck_type="2" data-sck_unlock="profiling" data-sck_ref="Google Maps" data-sck_index="1" class="BlockedBySmartCookieKit"></script>
			if(preg_match("/class\s*\=\s*[\'\"]BlockedBySmartCookieKit[\'\"]/i", $value['text'])){
				continue;
			}

			/*
			<script src="//platform.linkedin.com/in.js" type="text/javascript">lang: en_US</script>
			<script type="IN/Share" data-counter="top" data-onSuccess="share" data-url="https://helenstock.com/product/romantic-fashion/"></script>
			*/
			if(preg_match("/platform\.linkedin\.com\/in\.js/i", $value['text']) || preg_match("/type=[\"\']IN\/Share[\"\']/i", $value['text'])){
				continue;
			}

			/*
			<script id="mNCC" language="javascript">
			medianet_width="336";
			medianet_height="280";
			medianet_crid="656555462";
			medianet_versionId="3111299";
			</script>
			<script src="//contextual.media.net/nmedianet.js?cid=8CU33LCO0"></script>
			*/
			if((preg_match('/medianet_width/i', $value['text']) && preg_match('/medianet_height/i', $value['text'])) || preg_match("/contextual\.media\.net\/nmedianet\.js/i", $value['text'])){
				continue;
			}

			/*
			<script class="cmplz-stats">(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||fu);</script>
			<script class="cmplz-native">function complianz_enable_cookies(){console.log("enabling cookies");}</script>
			https://wordpress.org/plugins/complianz-gdpr/
			*/
			if(preg_match("/class\s*\=\s*[\"\']cmplz-(stats|native)\s*[\"\']/i", $value['text'])){
				continue;
			}

			/*
			Advanced noCaptcha & invisible Captcha
			var anr_onloadCallback=function(){
			};
			*/
			if(preg_match('/anr_onloadCallback/i', $value['text'])){
				continue;
			}

			$speedycache->render_blocking['js_tags_text'] = $speedycache->render_blocking['js_tags_text'].$value['text'];

			array_push($speedycache->render_blocking['tags'], $value);
		}
	}

	static function set_header_start_index(){
		global $speedycache;
		
		$head_tag = self::find_tags('<head', '>');
		
		$speedycache->render_blocking['header_start_index'] = 0;
		if(!empty($head_tag[0]) && !empty($head_tag[0]['start'])){
			$speedycache->render_blocking['header_start_index'] = $head_tag[0]['start'];
		}

	}

	static function reorder_tags($tags){
		// <script>jQuery('head').append('<style>' + arr_splits[i] + '</style>');</script>
		// <script>document.getElementById("id").innerHTML='<div> <span> <!--[if !IE]>--> xxx <!--<![endif]--> </span></div>';</script>
		$list = array();
		
		for ($i=0; $i < count($tags); $i++){
			for ($j=0; $j < count($tags); $j++){ 
				if($tags[$i]['start'] > $tags[$j]['start']){
					if($tags[$i]['end'] < $tags[$j]['end']){
						array_push($list, $i);
					}
				}
			}
		}

		foreach($list as $key => $value){
			unset($tags[$value]);
		}

		$sorter = array();
		$ret = array();

		foreach($tags as $ii => $va){
			$sorter[$ii] = $va['start'];
		}

		asort($sorter);

		foreach($sorter as $ii => $va){
			$ret[$ii] = $tags[$ii];
		}

		$tags = $ret;

		return $tags;
	}

	static function exclude_scripts($text){

		$excludeables = array(
			'/google_ad_client/',
			'/googlesyndication\.com/',
			'/app\.getresponse\.com/i',
			'/adsbygoogle/i',
			'/^<script[^\>]*>\s*gtag\([^\)]+\)\s*\;\s*<\/script>$/i',
			'/smarticon\.geotrust\.com\/si\.js/i',
			'/veedi\.com\/player\/embed\/veediEmbed\.js/i',
			'/cdn\.ampproject\.org/i',
			'/data-speedycache-render\=[\"\']false[\"\']/i',
			'/adserver\.adtechjp\.com/i',
			'/ib\.3lift\.com/i',
			'/adtradradservices\.com/i',
			'/static.clickpapa.com\/c\.js/i',
			'/clickpapa_ad_client/i',
			'/cts\.tradepub\.com/i',
			'/_areklam_target|ad\.arklm\.com/i',
			'/admatic\.com\.tr/i',
			'/ca\.cubecdn\.net/i',
			'/amazon-adsystem\.com\/widgets\/onejs/i',
			'/cdn\.playwire\.com\/bolt\/js\/zeus\/embed\.js/i',
			'/static\.mailerlite\.com/i',
		);
		
		$is_excludeable = false;

		foreach($excludeables as $excludeable){
			if(preg_match($excludeable, $text)){
				$is_excludeable = true;
				break;
			}
		}

		
		return $is_excludeable;
	}

	static function set_except($tags){
		global $speedycache;
		
		foreach($tags as $key => $value){
			$speedycache->render_blocking['except'] = $value['text'].$speedycache->render_blocking['except'];
		}
	}

	static function find_tags($start_string, $end_string, $html = false){
		global $speedycache;
		
		$data = $speedycache->render_blocking['html'];
		if(!empty($html)){
			$data = $html;
		}

		$list = array();
		$start_index = false;
		$end_index = false;

		for($i = 0; $i < strlen($data); $i++){
			if(substr($data, $i, strlen($start_string)) == $start_string){
				if(!$start_index && !$end_index){
					$start_index = $i;
				}
			}

			if(empty($start_index) || $i < $start_index){
				continue;
			}

			if(substr($data, $i, strlen($end_string)) !== $end_string){
				continue;
			}
			
			$end_index = $i + strlen($end_string) - 1;
			$text = substr($data, $start_index, ($end_index - $start_index + 1));

			if($html === false){
				$tag = self::get_tags($start_index, $text, $end_index);

				if($tag !== FALSE){
					array_push($list, $tag);
				}
			}else{
				array_push($list, array('start' => $start_index, 'end' => $end_index, 'text' => $text));
			}

			$start_index = false;
			$end_index = false;
		}

		return $list;
	}

	static function get_tags($start_index, $text, $end_index){
		global $speedycache;
		
		if($start_index <= $speedycache->render_blocking['header_start_index']){
			return false;
		}
		
		if($speedycache->render_blocking['except']){
			if(strpos($speedycache->render_blocking['except'], $text) === false){
				return array('start' => $start_index, 'end' => $end_index, 'text' => $text);
			}
			
			return false;
		}
		
		return array('start' => $start_index, 'end' => $end_index, 'text' => $text);
	}

	static function split_html_condition($tag){
		if(substr_count($tag, '<!--') !== substr_count($tag, '-->')){
			return false;
		}

		if(!preg_match("/\<\!--\s*\[if[^\>]+>/i", $tag, $start_cond)){
			return false;
		}

		if(!preg_match("/<\!\[endif\]-->/i", $tag, $end_cond)){
			return false;
		}
				
		$all = array();

		$script_tag = self::find_tags('<script', '</script>', $tag);
		$style_tags = self::find_tags('<style', '</style>', $tag);
		$link_tags = self::find_tags('<link', '>', $tag);

		$all = array_merge($script_tag, $style_tags, $link_tags);

		$all = self::reorder_tags($all);

		foreach($all as $key => &$value){
			$value['text'] = $start_cond[0].$value['text'].$end_cond[0];
		}

		return $all;
	}

	static function add_defer_attr($tags){
		$external_start = false;

		foreach($tags as $key => &$value){

			if(preg_match("/^<script/i", $value['text'])){
				if(preg_match("/var\s+[^\=\;\s\"\']+\s*\=\s*new\s+[^\(\)]+\(/i", $value['text'])){
					//var block_td_uid_2_58aab3b5b4eb1=new tdBlock()
					break;
				}else if(preg_match("/jQuery\(\s*window\s*\)\.load\(/i", $value['text']) || preg_match("/\\$\(\s*window\s*\)\.load\(/i", $value['text'])){
					//jQuery(window).load(function(){
					//$(window).load(function(){
					break;
				}else if(preg_match("/^<script[^\>]*>\s*jQuery\([^\)\(]+\)\.[a-z]+\(/i", $value['text']) && strpos($value['text'], "\n") === FALSE){
					//<script>jQuery("div").append("");</script>

					$value['text'] = self::defer_load_inline_js($value['text']);
				}else if(preg_match("/^<script[^\>]*>\s*\(function\(\\$\)\{[^\}\n]+\}\)\(jQuery\)\;\s*<\/script>/", $value['text'])){
					//<script>(function($){"use strict";$("html").removeClass("ut-no-js").addClass("ut-js js");})(jQuery);</script>

					$value['text'] = self::defer_load_inline_js($value['text']);
				}else if(preg_match("/^<script[^\>]+src=[\'\"][^\>]+>/i", $value['text'])){
					if(preg_match("/data-cfasync\=/i", $value['text'])){
						break;
					}

					if(preg_match("/googletagmanager\.com/i", $value['text'])){
						continue;
					}

					if(!preg_match("/\s+defer\s+/i", $value['text'])){
						$value['text'] = preg_replace("/<script\s+/", '<script defer ', $value['text']);
					}

					$external_start = true;
				}else{
					//inline js

					if(preg_match("/connect\.facebook\.net/i", $value['text']) && preg_match("/parentNode\.insertBefore/i", $value['text'])){
						// <script>(function(d, s, id){
						// var js, fjs=d.getElementsByTagName(s)[0];
						// if(d.getElementById(id)) return;
						// js=d.createElement(s); js.id=id;
						// js.async=true;
						// js.src="//connect.facebook.net/nl_NL/sdk.js#xfbml=1&version=v2.8&appId=1126044540802926";
						// fjs.parentNode.insertBefore(js, fjs);
						// }(document, 'script', 'facebook-jssdk'));</script>

						continue;
					}else if(preg_match("/<script[^\>]*>\s*_stq\s*\=\s*window\._stq/i", $value['text']) && preg_match("/_stq\.push\s*\([^\)]+\)\s*\;\s*<\/script>/i", $value['text'])){
						// <script type='text/javascript'>
						// _stq = window._stq || [];
						// _stq.push([ 'view', {v:'ext',j:'1:5.5',blog:'121052134',post:'88',tz:'3',srv:'www.bibersa.com'} ]);
						// _stq.push([ 'clickTrackerInit', '121052134', '88' ]);
						// </script>

						continue;
					}else{
						if($external_start){
							break;
						}else{
							if(preg_match("/var\s+wpforms(_settings|RecaptchaLoad|RecaptchaCallback)\s*\=/i", $value['text'])){
								// WPForms Lite
								// var wpforms_settings = {variable}
								// var wpformsRecaptchaLoad=function(){
								// var wpformsRecaptchaCallback=function
								continue;
							}

							if(preg_match("/window\.TL_Const/i", $value['text']) && preg_match("/var\s+TL_Const/i", $value['text'])){
								// Thrive Leads
								// if(!window.TL_Const){var TL_Const=
								continue;
							}

							if(preg_match("/<script[^\>]+application\/ld\+json[^\>]+>/i", $value['text'])){
								// <script type="application/ld+json">
								// {
								// "@context": "http://schema.org/",
								// "@type": "Product",
								// "name": "Product Name",
								// "image": "/default.png",
								// "aggregateRating": {
								// "@type": "AggregateRating",
								// "ratingValue": "5",
								// "reviewCount": "81"
								// }
								// }
								// </script>
								continue;
							}

							if(preg_match("/_translator_revolution_dropdown/i", $value['text'])){
								// <script>var _translator_revolution_dropdown=_translator_revolution_dropdown||{languages: ["en","fr","de"],excludeSelector: "code, #wpadminbar",locationWidget: false};</script>

								continue;
							}

							$value['text'] = self::defer_load_inline_js($value['text']);
						}
					}
				}
			}else if(preg_match("/^<(link|style)/i", $value['text'])){
				continue;
			}else if(preg_match("/<\!--\s*\[if/i", $value['text'])){
				preg_match_all("/<script[^\>]+src=[\'\"][^\>]+>/i", $value['text'], $src_number);
				preg_match_all("/<script[^\>]*/i", $value['text'], $script_tag_number);

				if(count($script_tag_number[0]) != count($src_number[0])){
					break;
				}

				if(preg_match("/<link|<style/i", $value['text'])){
					break;
				}

				if(!preg_match("/<script[^\>]+src=[\'\"][^\>]+>/i", $value['text'])){
					break;
				}

				if(preg_match("/data-cfasync\=/i", $value['text'])){
					break;
				}

				if(!preg_match("/<script[^\>]+defer[^\>]+>/i", $value['text'])){
					$value['text'] = preg_replace("/<script\s+/", '<script defer ', $value['text']);
				}
			}else{
				break;
			}
		}

		return $tags;
	}

	static function action($render_blocking_css = false, $make_defer = false){
		global $speedycache;
		
		$wpemojiSettings = '';
		$google_fonts = '';
		$bootstrapcdn = '';
		$inline_js = '';
		$document_ready_js = '';
		$third_part_js = '';
		$script = '';
		$style = '';
		
		//to remove tags
		$speedycache->render_blocking['tags'] = array_reverse($speedycache->render_blocking['tags']);
		
		foreach($speedycache->render_blocking['tags'] as $key => &$value){
			if(preg_match("/\<\!--\s*\[if[^\>]+>/i", $value['text'])){
				if($arr = self::split_html_condition($value['text'])){
					$style = '';
					$script = '';

					foreach($arr as $arr_key => $arr_value){
						if(preg_match("/\<\!--\s*\[if[^\>]+>(<link|<style)/i", $arr_value['text'])){
							$style = $style."\n".$arr_value['text'];
						}else if(preg_match("/\<\!--\s*\[if[^\>]+><script/i", $arr_value['text'])){
							$script = $script."\n".$arr_value['text'];
						}
					}
				}

				$value['text'] = $script;
				$speedycache->render_blocking['html'] = substr_replace($speedycache->render_blocking['html'], $style, $value['start'], ($value['end'] - $value['start'] + 1));
			}else if(preg_match("/^<script/i", $value['text'])){
				$speedycache->render_blocking['html'] = substr_replace($speedycache->render_blocking['html'], '', $value['start'], ($value['end'] - $value['start'] + 1));
			}else if(preg_match("/^<link[^\>]+(fonts|ajax)\.googleapis\.com[^\>]+>/", $value['text'])){
				if(!empty($speedycache->options['google_fonts'])){
					$speedycache->render_blocking['html'] = substr_replace($speedycache->render_blocking['html'], '', $value['start'], ($value['end'] - $value['start'] + 1));

					$google_fonts = $value['text']."\n".$google_fonts;
				}
			}else if(preg_match("/^<link[^\>]+(maxcdn)\.bootstrapcdn\.com[^\>]+>/", $value['text'])){
				$speedycache->render_blocking['html'] = substr_replace($speedycache->render_blocking['html'], '', $value['start'], ($value['end'] - $value['start'] + 1));

				$bootstrapcdn = $value['text']."\n".$bootstrapcdn;
			}
		}
		
		foreach($speedycache->render_blocking['tags'] as $key => &$value){
			
			if($value['text'] && preg_match("/^<script/i", $value['text'])){
				if(preg_match("/gravatar\.com\/js\/gprofiles\.js/i", $value['text']) || 
					preg_match("/use\.fontawesome\.com/i", $value['text']) || 
					preg_match("/s0\.wp\.com\/".SPEEDYCACHE_WP_CONTENT_DIR."\/js\/devicepx-jetpack\.js/i", $value['text'])){
					//<script type='text/javascript' src='http://s.gravatar.com/js/gprofiles.js?ver=2023Janaa'></script>
					//<script type='text/javascript' src='http://s0.wp.com/site-data/js/devicepx-jetpack.js?ver=201701'></script>
					//<script defer src="https://use.fontawesome.com/123456789.js"></script>

					if(!preg_match("/\sdefer\s/i", $value['text'])){
						$value['text'] = preg_replace("/<script\s+/", '<script defer ', $value['text']);
					}

					if(!preg_match("/\sasync\s/i", $value['text'])){
						$value['text'] = preg_replace("/<script\s+/", '<script async ', $value['text']);
					}

					unset($speedycache->render_blocking['tags'][$key]);
					$third_part_js = $value['text']."\n".$third_part_js;
				}else if(preg_match("/document\.addEventListener\(\s*[\"\']\s*DOMContentLoaded\s*[\"\']\s*,\s*function\s*\([^\)]*\)\s*\{/i", $value['text'])){
					//to remove jQuery(document) which contains window.attachEvent
					unset($speedycache->render_blocking['tags'][$key]);
					$document_ready_js = $value['text']."\n".$document_ready_js;
				}else if(preg_match("/^<script[^\>]*>\s*jQuery\(\s*document\s*\)\.ready\(/i", $value['text'])){
					// <script>
					// 	jQuery(document).ready(function($){
					// 	});
					// </script>

					if(preg_match("/jQuery\(\s*window\s*\)\.load\(/i", $value['text'])){
						//jQuery(window).load(function(){
						continue;
					}

					if(preg_match("/\\$\(\s*window\s*\)\.load\(/i", $value['text'])){
						//$(window).load(function(){
						continue;
					}

					if(preg_match("/var owl\s*=\s*\\$\([\'\"]\.products-carousels-/i", $value['text'])){
						//to exclude carousel of Master Slider
						//https://codecanyon.net/item/master-slider-wordpress-responsive-touch-slider
						//var owl=$('.products-carousels-99056136 #products');
						continue;
					}
					
					if(preg_match("/\}\s*\)\s*\;\s*<\/script>$/i", $value['text'])){
						$jqIsReady_func_name = 'jqIsReady_'.rand(100,999);
						$value['text'] = preg_replace("/(<script[^\>]*>)/i", "$1"."(function ".$jqIsReady_func_name."(){if(typeof jQuery === \"undefined\"){".$jqIsReady_func_name."();}else{", $value['text']);
						$value['text'] = preg_replace("/\s*(<\/script>)/i", "}})();"."$1", $value['text']);

						unset($speedycache->render_blocking['tags'][$key]);
						$document_ready_js = $value['text']."\n".$document_ready_js;
					}
				}else if(preg_match("/^<script[^\>]*>\s*window\.\_wpemojiSettings/", $value['text'])){
					//to remove window._wpemojiSettings from tags
					unset($speedycache->render_blocking['tags'][$key]);
					$wpemojiSettings = $wpemojiSettings."\n".$value['text'];
				}else if(!preg_match("/^<script[^\>]+src=[\'\"][^\>]+>/", $value['text'])){
					//to remove inline js which do not contain any function
					//<script>var _wpcf7={"loaderUrl":"sample"};</script>
					$tmp = $value['text'];

					// <script>/*<![CDATA[*/var THO_Front = THO_Front || {}; THO_Front.data = {"end_of_content_id":"tho-end","const":{"_e_click":1,"_engagement":2}}/*]]> */</script>
					$tmp = preg_replace("/<script[^\>]+>\s*\/\*\s*<\!\[CDATA\[\s*\*\//", "", $tmp);
					$tmp = preg_replace("/\/\*\s*\]\]>\s*\*\/\s*<\/script>/", "", $tmp);

					// to remove multi-line comments but it removes everything. it does not work properly
					$tmp = preg_replace("/\s*\/\*(.+)\*\/\s*/", '', $tmp);

					//var themifyScript causes "fixed header" issue on thepurplepumpkinblog.co.uk
					if(preg_match("/var\sthemifyScript/i", $tmp)){
						continue;
					}

					//<script data-cfasync="false" type="text/javascript">var lsjQuery = jQuery;</script>
					if(preg_match("/data-cfasync\=[\"\']false[\"\']/i", $tmp)){
						continue;
					}

					if(preg_match("/(function|jQuery|if)\s*\([^\)\(]+\)/i", $tmp)){
						if(!preg_match("/<script[^\>]*>\s*function heateorSssLoadEvent/i", $tmp)){
							//https://plugins.trac.wordpress.org/browser/sassy-social-share/trunk/includes/class-sassy-social-share-widgets.php#L72
							//https://plugins.trac.wordpress.org/browser/sassy-social-share/trunk/public/class-sassy-social-share-public.php#L104

							continue;
						}
					}

					//var block_td_uid_2_58aab3b5b4eb1=new tdBlock()
					if(preg_match("/var\s+[^\=\;\s\"\']+\s*\=\s*new\s+[^\(\)]+\(/i", $tmp)){
						continue;
					}

					//<script>var lsjQuery = jQuery;</script>
					if(preg_match("/var\s+[^\=\s]+\s*\=\s*jQuery\s*\;/i", $value['text'])){
						continue;
					}

					//<script>Abtf.css();</script>
					//<script>dtGlobals.logoEnabled=1;</script>
					//if var does not exist
					if(!preg_match("/var\s*[a-z0-9_]+\s*\=\s*[^\;]+\s*\;/i", $tmp)){
						continue;
					}

					//$=jQuery.noConflict()
					//var joblistin_caned_msgs=jQuery.parseJSON('[{\"title\":\"jobs description 1\",
					if(preg_match("/\=\s*jQuery\.(noConflict|parseJSON)\(/i", $tmp)){
						continue;
					}

					//$(".menu-item-has-children a")
					if(preg_match("/\\\$\s*\(\s*[\"\']/", $tmp)){
						continue;
					}

					/*
					<script>
					jQ_nxs(document).on('nxs_event_resizeend.menu_mini_expand', function(){
						//something
					});
					</script>
					*/
					if(preg_match("/\([^\)]+\)\.on\(\s*[\'\"][^\'\"]+[\'\"]\s*\,\s*function\(\)\{/", $tmp)){
						continue;
					}

					/*
					<script>
					videojs("vid1").videoJsResolutionSwitcher();
					var my_video_id = videojs("vid1");
					my_video_id.watermark({ file: "/site-data/uploads/2019/05/logo.png", xpos: 0, ypos: 0, xrepeat: 0, opacity: 1,clickable: true,url: "https://www.site.net"  });
					</script>
					*/
					if(preg_match("/videojs\([^\)\(]+\)\.videoJsResolutionSwitcher/", $tmp)){
						continue;
					}

					unset($speedycache->render_blocking['tags'][$key]);
					$inline_js = $value['text']."\n".$inline_js;

				}
			}
		}

		//to add Google Fonts at the end of page before js sources
		if(!empty($google_fonts)){
			//$google_fonts = self::combine_google_fonts($google_fonts);

			if(!empty($speedycache->options['google_fonts'])){
				
				if(preg_match('/speedycache-google-fonts/', $speedycache->render_blocking['html'])){
					$speedycache->render_blocking['html'] = str_replace('<noscript id="speedycache-google-fonts">', '<noscript id="speedycache-google-fonts">'.$google_fonts, $speedycache->render_blocking['html']);
				}else{
					$google_fonts = self::async_google_fonts($google_fonts);
					$speedycache->render_blocking['html'] = str_replace('</body>', $google_fonts."\n".'</body>', $speedycache->render_blocking['html']);
				}

			}
		}
		
		//to add BootstrapCDN at the end of page before js sources
		if(!empty($bootstrapcdn)){
			$speedycache->render_blocking['html'] = str_replace('</body>', $bootstrapcdn."\n".'</body>', $speedycache->render_blocking['html']);
		}

		//to add Inline Js before at the end of page before js sources
		if(!empty($inline_js)){
			$speedycache->render_blocking['html'] = str_replace('</body>', $inline_js."\n".'</body>', $speedycache->render_blocking['html']);
		}

		//to add third_part_js at the end of page
		if(!empty($third_part_js)){
			$speedycache->render_blocking['html'] = str_replace('</body>', $third_part_js."\n".'</body>', $speedycache->render_blocking['html']);
		}

		//to add defer and async attribute
		if(!empty($make_defer) || empty($speedycache->options['combine_js_enhanced'])){
			$speedycache->render_blocking['tags'] = self::add_defer_attr($speedycache->render_blocking['tags']);
		}

		//to add tags into footer
		$speedycache->render_blocking['tags'] = array_reverse($speedycache->render_blocking['tags']);
		foreach($speedycache->render_blocking['tags'] as $key => $value){
			if(preg_match("/^<script/i", $value['text'])){
				$speedycache->render_blocking['html'] = str_replace('</body>', $value['text']."\n".'</body>', $speedycache->render_blocking['html']);
			}else if(preg_match("/\<\!--\s*\[if[^\>]+>/i", $value['text'])){
				$speedycache->render_blocking['html'] = str_replace('</body>', $value['text']."\n".'</body>', $speedycache->render_blocking['html']);
			}
		}

		//to add document_ready_js at the end of page
		if(!empty($document_ready_js)){
			$speedycache->render_blocking['html'] = str_replace('</body>', $document_ready_js."\n".'</body>', $speedycache->render_blocking['html']);
		}

		//to add wpemojiSettings at the end of page
		if(!empty($wpemojiSettings)){
			$speedycache->render_blocking['html'] = str_replace('</body>', $wpemojiSettings."\n".'</body>', $speedycache->render_blocking['html']);
		}
		
		return preg_replace("/^\s+/m", '', $speedycache->render_blocking['html']);
	}

	static function async_google_fonts($fonts){
		if(preg_match("/\shref\=/", $fonts)){
			$fonts = '<noscript id="speedycache-google-fonts">'.$fonts.'</noscript>';
			$onload = "<script>document.addEventListener('DOMContentLoaded',function(){function speedycachegl(){var wgh=document.querySelector('noscript#speedycache-google-fonts').innerText, wgha=wgh.match(/<link[^\>]+>/gi);var i=0;for(i=0;i<wgha.length;i++){var wrpr=document.createElement('div');wrpr.innerHTML=wgha[i];document.body.appendChild(wrpr.firstChild);}}speedycachegl();});</script>";
			
			return $fonts."\n".$onload;
		}
		
		return $fonts;
	}

	static function combine_google_fonts($fonts){
		$family = '';
		$subset = '';

		preg_match_all("/fonts\.googleapis\.com\/css\?family\=([^\'\"]+)/si", $fonts, $arr);

		if(empty($arr[0])){
			return $fonts;
		}

		foreach($arr[0] as $key => $value){
			//to remove special chars
			$value = htmlspecialchars_decode($value);

			$parts = parse_url($value);
			parse_str($parts['query'], $query);

			$family = $query['family'];
			if(!empty($family)){
				$family = $family.'|'.$query['family'];
			}

			if(isset($query['subset']) && $query['subset']){
				
				$subset = $query['subset'];
				if(!empty($subset)){
					$subset = $subset.','.$query['subset'];
				}
			}
		}

		$family = str_replace(' ', '+', $family);
		if(!empty($subset)){
			$family.'&subset='.$subset;
		}

		return "<!--\n".$fonts."\n-->\n"."<link rel='stylesheet' id='speedycache-google-combined' href='http://fonts.googleapis.com/css?family=".$family."' type='text/css' media='all'/>";
	}

	static function defer_load_inline_js($script){
		if(preg_match("/<script[^\>]*>\s*\/\/\<\!\[CDATA\[\s*/", $script) && preg_match("/\/\/\]\]\>\s*<\/script>/", $script)){
			$script = preg_replace("/(<script[^\>]*>)\s*\/\/\<\!\[CDATA\[\s*/", "$1\n", $script);
			$script = preg_replace("/\/\/\]\]\>\s*(<\/script>)/", "\n$1", $script);
		}

		if(preg_match("/var\s+wpforms_conditional_logic/i", $script)){
			// to exclude the conditions of wpforms
			// <script type='text/javascript'>
			// /* <![CDATA[ */
			// var wpforms_conditional_logic = {"5616":{"17"}]],"action":"show"}}}
			// /* ]]> */
			// </script>
			return $script;
		}

		if(preg_match("/var\s+recaptchaWidgets/i", $script)){
			if(preg_match("/var\s+recaptchaCallback/i", $script)){
				// to exclude
				// https://github.com/IQComputing/wpcf7-recaptcha/blob/master/recaptcha-v2.php#L94
				return $script;
			}
		}

		if(preg_match('/function jqIsReady/i', $script)){
			return $script;
		}

		if(preg_match("/^<script[^\>]+>\s*<\/script>/i", $script)){
			// to exclude empty inline source
			// <script type="text/javascript" id="speedycachep-script-frontend"></script>
			return $script;
		}

		$script = preg_replace("/^(<script[^\>]*>)/i", "$1"."document.addEventListener('DOMContentLoaded',function(){", $script);
		$script = preg_replace("/\s*(<\/script>)/i", "});"."$1", $script);

		return $script;
	}
}statistics.php000064400000010433151526435070007460 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class Statistics{

	static function init($extension = false, $size = false){
		global $speedycache;
		$speedycache->settings['static_extension'] = $extension ? $extension : false;
		$speedycache->settings['static_size'] = $size ? $size : false;
	}

	static function get(){
		
		$desktop_files = get_option('speedycache_html');
		$desktop_size = round(get_option('speedycache_html_size')/1000, 2);
		$mobile_files = get_option('speedycache_mobile');
		$mobile_size = round(get_option('speedycache_mobile_size')/1000, 2);
		$js_files = get_option('speedycache_js');
		$js_size = round(get_option('speedycache_js_size')/1000, 2);
		$css_files = get_option('speedycache_css');
		$css_size = round(get_option('speedycache_css_size')/1000, 2);
		
		$stats = array();
		$stats['desktop'] = array('size' => $desktop_size, 'file' => $desktop_files);
		$stats['mobile'] = array('size' => $mobile_size, 'file' => $mobile_files);
		$stats['js'] = array('size' => $js_size, 'file' => $js_files);
		$stats['css'] = array('size' => $css_size, 'file' => $css_files);

		return $stats;
	}

	static function update_db(){
		global $speedycache;
		
		// We do not need stats if its a test
		if(!empty($_GET['test_speedycache'])){
			return;
		}

		$option_name = 'speedycache_' . $speedycache->settings['static_extension'];
		$option_name_for_size = $option_name . '_size';
		
		$current_opt = get_option($option_name);
		
		if(!empty($current_opt)){
			$current_opt = $current_opt + 1;
			update_option($option_name, $current_opt);
		}else{
			update_option($option_name, 1, null, 'yes');
		}

		$size_current_opt = get_option($option_name_for_size);

		if(!empty($size_current_opt)){
			$size_current_opt = $size_current_opt + $speedycache->settings['static_size'];
			update_option($option_name_for_size, $size_current_opt);
			return;
		}
		
		update_option($option_name_for_size, $speedycache->settings['static_size'], null, 'yes');

	}

	static function statics(){
		?>
		<div class="speedycache-block">
			<div class="speedycache-block-title">
				<h2 id="cache-statics-h2"><?php _e('Cache Statistics', 'speedycache'); ?></h2>
			</div>
			<div id="speedycache-cache-statics">
				<div id="speedycache-cache-statics-desktop" class="speedycache-card">
					<div class="speedycache-card-body">
						<div class="speedycache-stats-info">
							<span>Desktop Cache</span>
							<p id="speedycache-cache-statics-desktop-data">
								<span class="speedycache-size">0Kb</span><br/>
								<span class="speedycache-files">of 0 Items</span>
							</p>
						</div>
						<div class="speedycache-stat-icon">
							<i class="fas fa-desktop"></i>
							<!--<span class="dashicons dashicons-desktop"></span>-->
						</div>
					</div>
				</div>
				<div id="speedycache-cache-statics-mobile" class="speedycache-card">
					<div class="speedycache-card-body">
						<div class="speedycache-stats-info">
							<span>Mobile Cache</span>
							<p id="speedycache-cache-statics-mobile-data">
								<span class="speedycache-size">0Kb</span><br/>
								<span class="speedycache-files">of 0 Items</span></p>
						</div>
						<div class="speedycache-stat-icon">
							<i class="fas fa-mobile"></i>
						</div>
					</div>
				</div>
				<div id="speedycache-cache-statics-css" class="speedycache-card">
					<div class="speedycache-card-body">
						<div class="speedycache-stats-info">
							<span>Minified CSS</span>
							<p id="speedycache-cache-statics-css-data">
								<span class="speedycache-size">0Kb</span><br/>
								<span class="speedycache-files">of 0 Items</span>
							</p>
						</div>
						<div class="speedycache-stat-icon"><i class="fab fa-css3-alt"></i></div>
					</div>
				</div>
				<div id="speedycache-cache-statics-js" class="speedycache-card">
					<div class="speedycache-card-body">	
						<div class="speedycache-stats-info">
							<span>Minified JS</span>
							<p id="speedycache-cache-statics-js-data">
								<span class="speedycache-size">0Kb</span><br/>
								<span class="speedycache-files">of 0 Items</span>
							</p>
						</div>
						<div class="speedycache-stat-icon"><i class="fab fa-js-square"></i></div>
					</div>
				</div>
			</div>
		</div>
	<?php }

}

prooptimizations.php000064400000004144151526435070010722 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT');
}

class ProOptimizations{
	static $content = '';

	// function init(&$content){
		// self::$content = $content;
	// }
	
	static function defer_js(&$content){
		global $speedycache;

		\SpeedyCache\Enhanced::init();
		$content = \SpeedyCache\Enhanced::render_blocking($content);
	}
	
	static function delay_js(&$content){
		global $speedycache;

		\SpeedyCache\Enhanced::init();
		if(empty($speedycache->enhanced)){
			$speedycache->enhanced['html'] = $content;
		}

		$content = \SpeedyCache\Enhanced::delay_js($content);
	}
	
	static function unused_css(){
		$url = esc_url(speedycache_optserver('HTTP_HOST'). speedycache_optserver('REQUEST_URI'));

		if(strpos($url, '?test_speedycache') !== FALSE){
			\SpeedyCache\UnusedCss::generate(array($url));
		} else {
			\SpeedyCache\UnusedCss::schedule('speedycache_unused_css', array($url));
		}
	}
	
	static function critical_css(){
		$url = esc_url(speedycache_optserver('HTTP_HOST'). speedycache_optserver('REQUEST_URI'));

		if(strpos($url, '?test_speedycache') !== FALSE){
			\SpeedyCache\CriticalCss::generate(array($url));
		} else {
			\SpeedyCache\CriticalCss::schedule('speedycache_generate_ccss', array($url));
		}
	}
	
	static function img_lazy_load(&$content){

		// to disable for Ajax Load More on the pages
		if(speedycache_is_plugin_active('ajax-load-more/ajax-load-more.php') && !empty($_SERVER['REQUEST_URI']) && preg_match("/\/page\/\d+\//", sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])))){
			return;
		}

		$content = \SpeedyCache\Enhanced::lazy_load($content);
		$lazy_load_js = '';
		
		if(file_exists(SPEEDYCACHE_PRO_DIR . '/main/lazyload.php')){
			$lazy_load_js = \SpeedyCache\LazyLoad::get_js_source();
		}

		$content = preg_replace("/\s*<\/head\s*>/i", $lazy_load_js.'</head>', $content, 1);
	}
	
	static function remove_gfonts(&$content){
		if(!empty($speedycache->bloat['remove_gfonts'])){
			$content = preg_replace('/<link[^<>]*\/\/fonts\.(googleapis|google|gstatic)\.com[^<>]*>/i', '', $content);
		}
	}
}mobile.php000064400000003106151526435070006534 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class Mobile{

	static function cache(){
		global $speedycache;
		
		$speedycache->mobile_cache = array();
		$speedycache->mobile_cache['folder_name'] = 'mobile-cache';
		$speedycache->mobile_cache['wptouch'] = false;
	}

	static function update_htaccess($data){
		global $speedycache;
		
		preg_match("/RewriteEngine\sOn(.+)/is", $data, $out);
		$htaccess = "\n##### Start: Mobile Cache Rules #####\n";
		$htaccess .= $out[0];

		// Updates the moble cache htaccess rule according to wptouch
		if($speedycache->mobile_cache['wptouch']){
			$wptouch_rule = "RewriteCond %{HTTP:Cookie} !wptouch-pro-view=desktop";
			$htaccess = str_replace("RewriteCond %{HTTP:Profile}", $wptouch_rule."\n"."RewriteCond %{HTTP:Profile}", $htaccess);
		}

		/**
		* Structure of this array is
		*	searchable => replacer
		*/
		$rules = array(
			'RewriteCond %{HTTP:Cookie} !safirmobilswitcher=mobil' => 'RewriteCond %{HTTP:Cookie} !safirmobilswitcher=masaustu',
			'RewriteCond %{HTTP_USER_AGENT} !^.*' => 'RewriteCond %{HTTP_USER_AGENT} ^.*',
		);
		
		foreach($rules as $search => $replacement){
			$htaccess = str_replace($search, $replacement, $htaccess);
		}

		$htaccess = preg_replace('/\/speedycache\/'.preg_quote(SPEEDYCACHE_SERVER_HOST).'\/all\//', '/speedycache/'.SPEEDYCACHE_SERVER_HOST .'/'. $speedycache->mobile_cache['folder_name']."/", $htaccess);
		$htaccess .= "\n##### End: Mobile Cache Rules #####\n";

		return $htaccess;
	}

}
image.php000064400000214160151526435070006353 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

class Image{

	static function init(){
		global $speedycache, $speedycache_optm_method;
		
		$speedycache->image = array();
		$speedycache->image['upload_dir'] = wp_upload_dir();
		$speedycache->image['id'] = false;
		$speedycache->image['metadata'] = array();
		$speedycache->image['name'] = '';
		$speedycache->image['path'] = '';
		$speedycache->image['url'] = '';
		$speedycache->image['images'] = array();
		$speedycache->image['images_clone'] = array();
		$speedycache->image['disabled_method'] = 0;
		
		// Default settings for img optimization
		$speedycache->image['settings'] = array(
			'on_upload' => false,
			'automatic_optm' => false,
			'url_rewrite' => false,
			'compression_method' => 'gd',
			'compression_quality' => '70'
		);
		
		$speedycache_optm_method = array(
			'gd' => array(
				'title' => 'GD',
				'desc' => 'Compress using PHP\'s native Extension for compression and conversion.'
			),
			'imagick' => array(
				'title' => 'Imagick',
				'desc' => 'Imagick outputs better image quality after compression at the cost of a little bigger file size compared to GD.'
			),
			'cwebp' => array(
				'title' => 'cWebP',
				'desc' => 'cwebp is a utility which can be downloaded on your server and its fast and light on you server.'
			)
		);
		
		// Binaries for cwebp
		$speedycache->image['binaries'] = array(
			'WINNT' => ['cwebp-122-windows-x64.exe', 'gif2webp-122-windows-x64.exe'],
			'Linux' => ['cwebp-122-linux-x86-64', 'gif2webp-122-linux-x86-64']
		);
		
		if(array_key_exists(PHP_OS, $speedycache->image['binaries'])){
			$speedycache->image['cwebp_binary'] = $speedycache->image['binaries'][PHP_OS][0];
			$speedycache->image['cwebp_gif'] = $speedycache->image['binaries'][PHP_OS][1];
		}

		if($img_settings = get_option('speedycache_img')){
			$speedycache->image['settings'] = array_merge($speedycache->image['settings'], $img_settings);
			self::compression_method_checks();

			return;
		}
		
		self::compression_method_checks();
		update_option('speedycache_img', $speedycache->image['settings']);

	}

	static function total_reduction(){
		global $wpdb;
		
		$query = "SELECT sum(`meta_value`) as total FROM `".$wpdb->prefix."postmeta` WHERE `meta_key`= 'speedycache_optimisation_reduction'";
		$result = $wpdb->get_row( $query );
		
		if(!empty($result->total)){
			$reduced = ($result->total && $result->total > 0) ? $result->total : 0;
			
			return $reduced > 10000 ? $reduced/1000 : $reduced;	
		}
		
		return 0;
	}

	static function optimized_file_count(){
		global $wpdb;
		
		$query = "SELECT count(`meta_value`) as optimized FROM `".$wpdb->prefix."postmeta` WHERE `meta_key`= 'speedycache_optimisation'";
		$result = $wpdb->get_row($query);
		
		if($result->optimized && $result->optimized > 0){
			return $result->optimized;
		}
		
		return 0;
	}

	static function optm_img_count(){

		return self::count_query(array(
			'post_type' => 'attachment',
			'post_mime_type' => array('image/jpeg', 'image/png', 'image/gif'),
			'post_status' => 'inherit',
			'posts_per_page' => -1,
			'meta_query' => array(
				array(
					'key' => 'speedycache_optimisation',
					'compare' => 'EXISTS'
				),
				array(
					'key' => 'speedycache_optimisation',
					'value' => base64_encode('"destination_path"'),
					'compare' => 'LIKE'
				)
			)
		));
	}

	static function error_count(){

		return self::count_query(array(
			'post_type' => 'attachment',
			'post_mime_type' => array('image/jpeg', 'image/png', 'image/gif'),
			'post_status' => 'inherit',
			'posts_per_page' => -1,
			'meta_query' => array(
				array(
					'key' => 'speedycache_optimisation',
					'compare' => 'EXISTS'
				),
				array(
					'key' => 'speedycache_optimisation',
					'value' => base64_encode('"error_code"'),
					'compare' => 'LIKE'
				)
			)
		));
	}

	static function null_posts_groupby(){
		return '';
	}

	static function count_posts_fields(){
		return 'COUNT(*) as post_count_speedycache';
	}

	static function count_query($query_images_args){
		add_filter('posts_fields', '\SpeedyCache\Image::count_posts_fields');
		add_filter('posts_groupby', '\SpeedyCache\Image::null_posts_groupby');

		unset($query_images_args['offset']);
		unset($query_images_args['order']);
		unset($query_images_args['orderby']);

		$query_images_args['posts_per_page'] = -1;

		$query_image = new \WP_Query( $query_images_args );

		return $query_image->posts[0]->post_count_speedycache;
	}

	static function image_count(){

		return self::count_query(array(
			'post_type' => 'attachment',
			'post_mime_type' => array('image/jpeg', 'image/png', 'image/gif'),
			'post_status' => 'inherit',
			'posts_per_page' => -1,
			'meta_query' => array(
				array(
					'key' => '_wp_attachment_metadata',
					'compare' => 'EXISTS'
				)
			)
		));
	}

	static function uncompressed_count(){

		return self::count_query(array(
			'post_type' => 'attachment',
			'post_mime_type' => array('image/jpeg', 'image/png', 'image/gif'),
			'post_status' => 'inherit',
			'posts_per_page' => -1,
			'meta_query' => array(
				array(
					'key' => 'speedycache_optimisation',
					'compare' => 'NOT EXISTS'
				)
			)
		));
	}

	static function unoptimized(){
		global $speedycache;
		
		$tmp_image = array();

		$optimization_data = get_post_meta($speedycache->image['id'], 'speedycache_optimisation', true);
		$optm_json = base64_decode($optimization_data);
		
		if(empty($optm_json)){
			$percentage = 100 / count($speedycache->image['images']);
			
			return array('meta_optimized' => array(), 'images' => $speedycache->image['images'], 'total_reduction' => 0, 'percentage' => $percentage);
		}

		$optm_json = json_decode($optm_json, true);
		$meta_optimized = self::object_to_array($optm_json);
		$percentage = count($meta_optimized) * 100/count($speedycache->image['images']);
		
		foreach($speedycache->image['images'] as $key => $value){
			$exist = false;

			foreach($meta_optimized as $meta_key => $meta_value){
				if($value['file'] == $meta_value['file']){
					$exist = true;
					//break;
				}
			}

			if(empty($exist)){
				array_push($tmp_image, $value);
			}
		}

		//START: total reduction
		$total_reduction = 0;
		
		foreach($meta_optimized as $m_key => $m_value){
			$m_value['reduction'] = isset($m_value['reduction']) ? $m_value['reduction'] : 0;
			
			if($m_key == 0){
				$reduction = $m_value['reduction'];
			}
			
			$total_reduction += $m_value['reduction'];
		}
		//END: total reduction

		if(count($tmp_image) <= 0){
			return array('meta_optimized' => array(), 'images' => array(), 'total_reduction' => 0);
		}

		$last = speedycache_optget('last');
		if(!empty($last)){
			if(preg_match('/last-(\d+)/', $last, $last_number)){
				if(count($tmp_image) > 5){
					$tmp_image = array_slice($tmp_image, $last_number[1]*-1, 1);
				}
			}
		}

		return array('meta_optimized' => $meta_optimized, 'images' => array_slice($tmp_image, 0, 1), 'total_reduction' => $total_reduction, 'percentage' => $percentage);
	}

	static function object_to_array($obj){
		if(is_object($obj)){
			$obj = (array) $obj;
		}
		
		if(!is_array($obj)){
			$new = $obj;
			return $new;
		}
		
		$new = array();
		foreach($obj as $key => $val){
			$new[$key] = self::object_to_array($val);
		}
		return $new;
	}

	static function reorder_by_dimensions(){
		global $speedycache;
		
		$tmp = $speedycache->image['images'];

		foreach($tmp as $key => $value){
			$width_list[$key] = $value['width'];
		}

		array_multisort($width_list, SORT_DESC, $tmp);
		
		return $tmp;
	}

	static function optimize_single($id = null){
		global $speedycache;

		if(!empty($id)){
			self::init();
		}

		self::set_id($id);
		self::set_meta_data();

		if(wp_next_scheduled('speedycache_auto_optm', array($speedycache->image['id']))){
			wp_clear_scheduled_hook('speedycache_auto_optm' , array($speedycache->image['id']));
		}

		if(empty($speedycache->image['id'])){
			return array('finish', 'success'); 
		}

		if(!isset($speedycache->image['metadata']['file']) && !empty($speedycache->image['id'])){
			$meta_optimized = array();
			$meta_optimized[0]['time'] = time();
			$meta_optimized[0]['id'] = $speedycache->image['id'];
			$meta_optimized[0]['error_code'] = 17;

			update_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction', 0);
			update_post_meta($speedycache->image['id'], 'speedycache_optimisation', base64_encode(json_encode($meta_optimized)));

			return array('Image has been optimized', 'success', $speedycache->image['id'], 100);
		}

		self::set_name();
		self::set_path();
		self::set_url();
		self::set_images();

		if(!empty($speedycache->image['id']) && count($speedycache->image['images']) == 0){
			$meta_optimized = array();
			$meta_optimized[0]['time'] = time();
			$meta_optimized[0]['id'] = $speedycache->image['id'];
			$meta_optimized[0]['error_code'] = 18;

			update_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction', 0);
			update_post_meta($speedycache->image['id'], 'speedycache_optimisation', base64_encode(json_encode($meta_optimized)));

			return array('Image has been optimized', 'success', $speedycache->image['id'], 100);
		}

		$error_exist = false;
		$meta_optimized = array();
		$total_reduction = 0;
		
		$speedycache->image['images'] = self::unique_array($speedycache->image['images']);
		$speedycache->image['images'] = self::reorder_by_dimensions();

		$speedycache->image['images_clone'] = $speedycache->image['images'];

		$unoptimized = self::unoptimized();
		$speedycache->image['images'] = $unoptimized['images'];
		$meta_optimized = $unoptimized['meta_optimized'];
		$total_reduction = $unoptimized['total_reduction'];
		$percentage = isset($unoptimized['percentage']) && $unoptimized['percentage'] ? $unoptimized['percentage'] : 0;

		if(count($speedycache->image['images']) == 0){
			return array('Image has been optimized', 'success', '', 100);
		}

		foreach($speedycache->image['images'] as $key => $value){
		
			$res = self::compress($value);
			
			if(!empty($res['success'])){
				$value['destination_path'] = $res['destination_path'];
				$value['reduction'] = $res['reduction'];

				$total_reduction += $value['reduction'];

				$value['time'] = time();
				$value['id'] = $speedycache->image['id'];
				
				array_push($meta_optimized, $value);
			}else{
				if(!isset($res['error_code']) && isset($res['error_message'])){
					return array($res['error_message'], 'error');
					break;
				}

				if(in_array($res['error_code'] , array(2, 6, 7, 11, 19, 20, 22, 23))){
					return array($res['error_message'], 'error');
					break;
				}

				$value['error_code'] = $res['error_code'];
				$error_exist = true;
			}

			$value['time'] = time();
			$value['id'] = $speedycache->image['id'];

			if(!empty($value['error_code'])){
				if($value['error_code'] != 8 || ($value['error_code'] == 8 && $key === 0)){
					array_push($meta_optimized, $value);
				}
			}
		}
		
		$percentage = self::update_meta($total_reduction, $meta_optimized);

		return array('Image has been optimized', 'success', $speedycache->image['id'], $percentage, $total_reduction);
	}

	static function update_meta($total_reduction, $meta_optimized){
		global $speedycache;
		
		if(isset($meta_optimized[0]) && isset($meta_optimized[0]['error_code']) && $meta_optimized[0]['error_code']){

			update_post_meta($speedycache->image['id'], 'speedycache_optimisation', base64_encode(json_encode($meta_optimized)));
			update_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction', 0);

			return 100;
		}

		$percentage = 0;
		$meta_temp = array();
		
		foreach($speedycache->image['images_clone'] as $key => $value){
			$backup_file = $value['file'];
			
			$value['file'] = preg_replace('/.(jpg|jpeg|png|gif)$/', '.webp', $value['file']);
			
			if(!file_exists($value['file']) || !file_exists($backup_file)){
				continue;
			}

			$diff = filesize($backup_file) - filesize($value['file']);
			$diff = $diff > 0 ? $diff : 0;

			$value['destination_path'] = $backup_file;
			$value['reduction'] = $diff;
			$value['time'] = time();
			$value['id'] = $speedycache->image['id'];

			array_push($meta_temp, $value);
		}

		foreach($meta_optimized as $m_key => $m_value){
			if(empty($m_value['error_code'])){
				continue;
			}

			$exist = false;

			for($i=0; $i < count($meta_temp); $i++){
				if($meta_temp['file'] == $m_value['file']){
					$exist = true;
				}
			}

			if(empty($exist)){
				$m_value['destination_path'] = '';
				$m_value['reduction'] = 0;
				$m_value['time'] = time();
				$m_value['id'] = $speedycache->image['id'];

				array_push($meta_temp, $m_value);
			}
		}
		
		if(count($meta_temp) > 0){
			$percentage = count($meta_temp)*100/count($speedycache->image['images_clone']);
		}else{
			$percentage = 0;
		}

		update_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction', $total_reduction);
		update_post_meta($speedycache->image['id'], 'speedycache_optimisation', base64_encode(json_encode($meta_temp)));

		return $percentage;
	}

	static function compress($source_image){
		global $speedycache;

		/*
			Error Codes
			2 = in backup folder parent folder not writable
			3 = no need to optimize
			4 = source is not writable
			5 = destination is not writable
			6 = ImageMagick library is not avaliable
			7 = Error via api
			8 = Source file does not exist
			9 = Image size exceed 5mb limit while processing
		   11 = Empty Name
		   12 = Forbidden
		   13 = CloudFlare to restrict access
		   14 = No Extension
		   15 = Image size is 0Kb
		   16 = Corrupted Image
		   17 = Empty Metadata
		   18 = No Image
		   19 = webp is not saved
		   20 = file size of destination_move_source_path is zero
		   21 = Unacceptable file type
		   22 = Unable to Convert Image using cwebp.
		   23 = The URL of the image has webp extension.
		*/

		// if the url starts with /wp-content
		if(preg_match('/^\/' . SPEEDYCACHE_WP_CONTENT_DIR . '/i', $source_image['url'])){
			$source_image['url'] = home_url().$source_image['url'];
		}

		$source_path = $source_image['file'];
		$res_backup = array('success' => true, 'error_message' => '');
		$webp_path = preg_replace('/.(jpe?g|png|gif)$/', '.webp', $source_path);

		if(strlen($speedycache->image['name']) === 0){
			return array('success' => false, 'error_code' => 11);
		}

		if(!file_exists($source_path)){
			return array('success' => false, 'error_code' => 8);
		}

		if(!pathinfo($source_image['url'], PATHINFO_EXTENSION)){
			return array('success' => false, 'error_code' => 14);
		}

		// If the URL of the image is a webp
		if(pathinfo($source_image['url'], PATHINFO_EXTENSION) == 'webp' && file_exists($webp_path)){
			return array('success' => false, 'error_code' => 23);
		}

		if(@filesize($source_path) > 5000000){
			return array("success" => false, 'error_code' => 9);
		}

		if(!self::allowed_mime($source_path)){
			return array('success' => false, 'error_code' => 21);
		}

		if(!self::path_is_image($source_path)){
			return array('success' => false, 'error_code' => 16);
		}

		if(filesize($source_path) == 0){
			return array('success' => false, 'error_code' => 15);
		}

		if(@rename($source_path, $source_path.'_writabletest')){
			rename($source_path.'_writabletest', $source_path);
		}else{
			return array('success' => false, 'error_message' => $source_path . ' is not writable', 'error_code' => 4);
		}

		$optm_result = self::start_optimization($source_path); // here we need to plugin compression static function
		
		if(empty($optm_result['success'])){
			//NOTE:Place some error Message here.
			return $optm_result;
		}

		if(!file_exists($webp_path)){
			return array('success' => false, 'error_code' => 19, 'error_message' => $webp_path . ' destination_path is not saved');
		}
		
		if(filesize($webp_path) <= 0){
			return array('success' => false, 'error_code' => 20, 'error_message' => $webp_path . ' file size of destination_path is zero');
		}

		$diff = self::compare_sizes($source_path, $webp_path);
		return array('success' => true, 'destination_path' => $webp_path, 'reduction' => $diff);
	}


	static function start_optimization($img){
		global $speedycache;

		switch($speedycache->image['settings']['compression_method']){
			case 'gd': 
				return self::gd_webp($img);
				
			case 'imagick':
				return self::imagick_webp($img);
				
			case 'cwebp':
				if(defined('SPEEDYCACHE_PRO')){					
					return \SpeedyCache\Image::cwebp_convert($img);
				}
				
				return array('success' => false, 'error_message' => 'SpeedyCache cwebp is a Pro feature');
				
			default:
				return array('success' => false,  'error_message' => 'The provided conversion method is not valid');
		}
	}

	static function path_is_image($source_path){
		$size = getimagesize($source_path);

		if(empty($size)){
			return false;
		}

		return true;
	}

	static function get_quality($img){
		$dimensions = $img->getImageGeometry();
		
		if($dimensions['width'] < 200 && $dimensions['height'] < 200){
			return 85;
		}

		return 90;
	}

	static function compare_sizes($source_path, $destination_path){
		$diff = filesize($source_path) - filesize($destination_path);

		return ($diff > 0) ? $diff : 1;
	}


	//TODO:: Will need it when we will add non webp compression
	static function create_backup_folder($destination_path){
		global $speedycache;
		
		$destination_path = str_replace($speedycache->image['upload_dir']['basedir'], '', $destination_path);
		$path_arr = explode('/', $destination_path);

		$path = $speedycache->image['upload_dir']['basedir'];

		for ($i=1; $i < count($path_arr) - 1; $i++){
			$parent_path = $path;
			$path = $path.'/'.$path_arr[$i];

			if(is_dir($path)){
				continue;
			}
			
			if(@mkdir($path, 0755, true)){
				//
			}else{
				//warning
				if($path_arr[$i] == 'speedycache-backup'){
					//toDO: to stop cron job and warn the user
				}

				return array('success' => false, 'error_message' => $parent_path.' is not writable', 'error_code' => 2);
			}
		}

		return array('success' => true, 'error_message' => '');
	}

	static function set_id($id = null){
		global $speedycache;
		
		$get_id = speedycache_optget('id');
		
		if(!empty($get_id)){
			$speedycache->image['id'] = intval($get_id);
		}elseif(!empty($id)){
			$speedycache->image['id'] = intval($id);
		}else{
			$speedycache->image['id'] = self::get_first_id();
		}
	}

	static function set_images(){
		global $speedycache;
		
		if(empty($speedycache->image['metadata']['file'])){
			return;
		}

		$arr = array(
			'file' => $speedycache->image['upload_dir']['basedir'].'/'.$speedycache->image['metadata']['file'],
			'url' => $speedycache->image['upload_dir']['baseurl'].'/'.$speedycache->image['metadata']['file'],
			'width' => $speedycache->image['metadata']['width'],
			'height' => $speedycache->image['metadata']['height'],
			'mime_type' => ''
		);
		
		array_push($speedycache->image['images'], $arr);

		$i = 0;
		$image_error = false;

		if(!is_array($speedycache->image['metadata']['sizes'])){
			if(empty($image_error)){
				self::not_in_metadata();
			}
		}

		foreach((array)$speedycache->image['metadata']['sizes'] as $key => $value){
			$value['url'] = $speedycache->image['url'].$value['file'];
			$value['file'] = $speedycache->image['path'].$value['file'];
			$value['mime_type'] = isset($value['mime-type']) ? $value['mime-type'] : '';

			unset($value['mime-type']);

			if($i == 0){
				if(self::not_found(self::get_correct_url($speedycache->image['upload_dir']['baseurl'].'/'.$speedycache->image['metadata']['file']))){
					$image_error = true;
					break;
				}
			}

			if(!self::not_found(self::get_correct_url($value['url'])) && self::allowed_mime($value['file'])){
				array_push($speedycache->image['images'], $value);
			}

			$i++;
		}

		if(empty($image_error)){
			self::not_in_metadata();
		}
	}

	static function get_correct_url($path){
		if(preg_match('/^\/'.SPEEDYCACHE_WP_CONTENT_DIR.'/i', $path)){
			
			// content_url() must return HTTP but it return /wp-content so we need to check
			if(content_url() == '/'.SPEEDYCACHE_WP_CONTENT_DIR && home_url() == site_url()){
				$path = home_url().$path;
			}
		}

		return $path;
	}

	static function not_in_metadata(){
		global $speedycache;
		
		$paths = array();

		foreach($speedycache->image['images'] as $key => $value){
			array_push($paths, $value['file']);
		}
		
		$files = glob($speedycache->image['path'].$speedycache->image['name'].'-'.'*');

		foreach((array)$files as $file){
			if(@filesize($file) > 1000000){
				continue;
			}

			if(!preg_match('/\.(jpg|jpeg|jpe|png|gif)$/i', $file)){
				continue;
			}

			$exp_dos = explode('/',$file);
			$basename = end($exp_dos);

			if(in_array($file, $paths)){
				continue;
			}
			
			if(!preg_match('/'.preg_quote($speedycache->image['name'], '/').'-(\d+)x(\d+)\..+/', $basename, $dimensions)){
				continue;
			}
			
			$value = array(
				'url' => $speedycache->image['url'].$basename,
				'file' => $file,
				'width' => $dimensions[1],
				'height' => $dimensions[2],
			);

			if(!self::not_found($value['url'])){
				array_push($speedycache->image['images'], $value);
			}
		}
	}

	static function set_path(){
		global $speedycache;
		
		$speedycache->image['path'] = $speedycache->image['upload_dir']['basedir'].'/'.preg_replace('/'.preg_quote($speedycache->image['name'], '/').'.+/', '', $speedycache->image['metadata']['file']);
	}

	static function set_url(){
		global $speedycache;
		
		$speedycache->image['url'] = $speedycache->image['upload_dir']['baseurl'].'/'.preg_replace('/'.preg_quote($speedycache->image['name'], '/').'.+/', '', $speedycache->image['metadata']['file']);
	}

	static function set_name(){
		global $speedycache;
		
		if(empty($speedycache->image['metadata'])){
			return;
		}

		if(isset($speedycache->image['metadata']['sizes']) && count($speedycache->image['metadata']['sizes']) > 0){
			$array_values = array_values($speedycache->image['metadata']['sizes']);
			$speedycache->image['name'] = preg_replace('/-'.$array_values[0]['width'].'x'.$array_values[0]['height'].'.+/', '', $array_values[0]['file']);

			if(!$speedycache->image['name']){
				$speedycache->image['name'] = substr($speedycache->image['metadata']['file'], strrpos($speedycache->image['metadata']['file'], '/') + 1);
			}
			
			return;
		}

		$info = pathinfo($speedycache->image['metadata']['file']);
		$speedycache->image['name'] =  basename($speedycache->image['metadata']['file'],'.'.$info['extension']);

		//$this->name = substr($this->metadata['file'], strrpos($this->metadata['file'], '/') + 1);
	}

	static function set_meta_data(){
		global $speedycache;
		
		$speedycache->image['metadata'] = wp_get_attachment_metadata($speedycache->image['id']);
	}

	//to get last image which is not optimized
	static function get_first_id(){

		$query_image = new \WP_Query(array(
			'order' => 'DESC',
			'orderby' => 'ID',
			'post_type' => 'attachment', 
			'post_mime_type' => 'image/jpeg, image/png, image/gif', 
			'post_status' => 'inherit',
			'posts_per_page' => 1,
			'meta_query' => array(
				array(
					'key' => 'speedycache_optimisation',
					'compare' => 'NOT EXISTS'
				),
				array(
					'key' => '_wp_attachment_metadata',
					'compare' => 'EXISTS'
				)
			)
		));

		return count($query_image->posts) == 1 ? $query_image->posts[0]->ID : false;
	}

	static function statics_data(){
		$res = array(
			'total_image_number' => self::image_count(),
			'error' => self::error_count(),
			'optimized' => self::optimized_file_count(),
			'uncompressed' => self::uncompressed_count(),
			'reduction' => self::total_reduction(),
			'percent' => 0,
		);

		if($res['optimized'] > 0){
			$res['percent'] = ($res['optimized'] - $res['error']) * 100/$res['optimized'];
		}else{
			$res['percent'] = 0;
		}
		
		$res['percent'] = number_format($res['percent'], 2);
		$res['reduction'] = $res['reduction'];
		
		return $res;
	}

	static function revert_all(){
		global $speedycache;
		
		if(!current_user_can('manage_options')){
			wp_die('Must Be admin');
		}

		$images = new \WP_Query(array(
			'order' => 'DESC',
			'orderby' => 'ID',
			'post_type' => 'attachment',
			'post_mime_type' => array('image/jpeg', 'image/png', 'image/gif'),
			'post_status' => 'inherit',
			'posts_per_page' => -1,
			'meta_query' => array(
				array(
					'key' => 'speedycache_optimisation',
					'compare' => 'EXISTS'
				)
			)
		));

		$failed = true;
		
		if(count($images->posts) <= 100){
			
			if($images->posts && count($images->posts) > 0){
				foreach($images->posts as $key => $post){
					$speedycache->image['id'] = $post->ID;
					$result = self::revert();
					
					if($result['success'] === true){
						$failed = false;
					}
				}
			}
			
			if(!empty($failed)){
				wp_send_json(array('success' => false, 'message' => __('Files can\'t be reverted', 'speedycache'))); 
			}
			
			wp_send_json(array('success' => true));
		}

		$schedule_posts = [];
		foreach($images->posts as $key => $post){
			
			if(100 === count($schedule_posts) || !empty($erase)){
				$schedule_posts = [];
			}

			$erase = false; // Flag to unset the $scheduled_posts
			
			$schedule_posts[] = $post->ID;

			// Check if we have reached 99 and make sure its not the last index
			if(count($schedule_posts) <= 99 && $key !== (count($images->posts) - 1)){
				continue;
			}
			
			// Skip if alredy on schedule list.
			if(wp_next_scheduled('speedycache_img_delete', array($schedule_posts))){
				$erase = true;
				continue;
			}
		
			$scheduled = self::get_optimization_schedule(array('speedycache_img_delete'));
			$time = time();
		
			if(!empty($scheduled) && isset(end($scheduled)['time'])){
				// getting the last index to get the last scheduled event
				$time = end($scheduled)['time'];
			}
			
			$final_schd_time = $time + 10;
		
			if(!wp_next_scheduled('speedycache_img_delete', array($schedule_posts))){
				wp_schedule_single_event($final_schd_time, 'speedycache_img_delete', array($schedule_posts));
				
				continue;
			}
		}

		wp_send_json(array('success' => true));
	}

	// Schedule deletion of image to reduce load on the server at a single time.
	static function scheduled_delete($img_id){
		global $speedycache;
		
		if(empty($img_id)){
			return;
		}

		if(is_scalar($img_id)){
			$speedycache->image['id'] = $img_id;
			self::revert();
			return;
		}
		
		foreach($img_id as $id){
			$speedycache->image['id'] = $id;
			self::revert();
		}
	}

	// Reverts a single image
	static function revert(){
		global $speedycache;
		
		if(empty($speedycache->image['id'])){
			return array('success' => false);
		}
		
		$optimization_data = get_post_meta($speedycache->image['id'], 'speedycache_optimisation', true);

		// optm = optimization
		$optm_json = base64_decode($optimization_data);
		$optm_json = json_decode($optm_json, true);
		
		if(empty($optm_json)){
			return array('success' => false);
		}

		if(!empty($optm_json) && is_array($optm_json) && count($optm_json) == 1 && !empty($optm_json[0])){
			if(!empty($optm_json[0]['error_code']) && $optm_json[0]['error_code'] == 18){
				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');

				return array('success' => true);
			}
		}

		$result = false;

		$optm_json = array_reverse($optm_json);
		$error_numbers = 0;
		
		foreach($optm_json as $key => $image){

			if(@!is_writable($image['file'])){
				if(isset($speedycache->image['metadata']['file']) && preg_match('/'.preg_quote($speedycache->image['metadata']['file'], '/').'/', $image['url'])){
					if(file_exists($image['file'])){
						$result = array('success' => true, 'message' => $image['file'].' is not writable');
						break;
					}
					
					delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
					delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');
				}
			}

			if(
				!empty($image['url']) && 
				!preg_match('/\.webp$/', $image['url']) && 
				isset($image['destination_path']) && 
				file_exists($image['destination_path']) &&
				(pathinfo($image['destination_path'], PATHINFO_EXTENSION) == 'webp')
			){
				@unlink($image['file']);

				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');
				$result = array('success' => true);
				
				continue;
			}

			if(!empty($image['error_code'])){
				if(isset($speedycache->image['metadata']['file']) && preg_match('/'.preg_quote($speedycache->image['metadata']['file'], '/').'/', $image['url'])){
					delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
					delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');
					$result = array('success' => true);
				}else{
					$error_numbers++;

					if($error_numbers == count($optm_json)){
						delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
						delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');
						$result = array('success' => true);
					}
				}
				
				continue;
			}

			if(preg_match('/'.preg_quote($speedycache->image['metadata']['file'], '/').'/', $image['url'])){
				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation');
				delete_post_meta($speedycache->image['id'], 'speedycache_optimisation_reduction');
				$result = array('success' => true);
			}

		}
		
		return $result;
	}

	static function revert_on_delete($id){
		global $speedycache;
		
		if(!wp_attachment_is_image($id)){
			return;
		}
		
		$speedycache->image['id'] = $id;
		
		self::revert();
	}

	static function get_error_text($id){
		
		//Error Codes
		$errors = array(
			2 => __('In backup folder parent folder not writable', 'speedycache'),
			3 => __('No need to optimize', 'speedycache'),
			4 => __('Source is not writable', 'speedycache'),
			5 => __('Destination is not writable', 'speedycache'),
			6 => __('ImageMagick library is not avaliable', 'speedycache'),
			7 => __('Error via api', 'speedycache'),
			8 => __('Source file does not exist', 'speedycache'),
			9 => __('Image size exceed 20mb limit while processing', 'speedycache'),
		   11 => __('Empty Name', 'speedycache'),
		   12 => __('Forbidden', 'speedycache'),
		   13 => __('CloudFlare to restrict access', 'speedycache'),
		   14 => __('No Extension', 'speedycache'),
		   15 => __('Image size is 0Kb', 'speedycache'),
		   16 => __('Corrupted Image', 'speedycache'),
		   17 => __('Empty metadata', 'speedycache'),
		   18 => __('No Image', 'speedycache'),
		   19 => __('destination_move_source_path is not saved', 'speedycache'),
		   20 => __('file size of destination_move_source_path is zero', 'speedycache'),
		   21 => __('Unacceptable file type', 'speedycache'),
		   23 => __('WEBP create by other tool', 'speedycache'),
		);

		return isset($errors[$id]) ? $errors[$id] : 'Unkown error code';
	}

	// TODO:: Will use it when we will do non-webp compression
	static function backup_folder_exist(){
		global $speedycache;
		
		$backup_folder_path = $speedycache->image['upload_dir']['basedir'].'/speedycache-backup';

		if(is_dir($backup_folder_path)){
			return true;
		}

		if(@mkdir($backup_folder_path, 0755, true)){
			return true;
		}
		return false;

	}

	static function push_main_image($arr){
		if(!isset($arr[0]) || isset($arr[0]->error_code)){
			return $arr;
		}

		$main = clone $arr[0];
		$total_reduction = 0;

		foreach($arr as $std_key => $std_value){
			if(!isset($std_value->error_code)){
				if(isset($std_value->reduction) && $std_value->reduction){
					$total_reduction = $total_reduction + $std_value->reduction;
				}
			}
		}

		$main->reduction = $total_reduction;

		array_unshift($arr, $main);

		return $arr;
	}

	static function list_content($query_images_args = array()){
		global $speedycache;
		
		remove_filter('posts_fields', '\SpeedyCache\Image::count_posts_fields'); //was causing bug
		
		$query_image = new \WP_Query( $query_images_args );
		$return_output = '';
		
		if(empty($query_image->posts) || count($query_image->posts) <= 0){
			return self::get_empty_row();
		}
		
		$count = 0;
		foreach($query_image->posts as $key => $post){
			$count++;
			$value_json = get_post_meta($post->ID, 'speedycache_optimisation', true);
			$tmpvalue_json = base64_decode($value_json);
			
			$std = json_decode($tmpvalue_json);

			$revert = true;

			$std = self::push_main_image($std);
			
			foreach($std as $std_key => $std_value){
				
				$content = ($std_key === 0) ? self::get_row() : self::get_child_row();

				if(empty($content)){
					continue;
				}

				$std_value->destination_path = isset($std_value->destination_path) ? $std_value->destination_path : '';
				$std_value->reduction = isset($std_value->reduction) ? $std_value->reduction : 0;
				
				if($std_key === 0 && $revert){
					$revert_button = '';
				}else{
					$revert_button = 'display:none;';
				}

				if(isset($std_value->error_code) && $std_value->error_code == 8){
					$revert_button = 'display:none;';
				}

				if(file_exists($std_value->destination_path)){
					$backup_url = $std_value->url.'?v='.time();
					$backup_title = 'Original Image';
					$backup_error_style = '';
				}else{
					if(isset($std_value->error_code) && $std_value->error_code){
						$backup_url = get_edit_post_link($std_value->id);
						$backup_title = self::get_error_text($std_value->error_code);
						$backup_error_style = 'color: #FF0000;cursor:pointer;font-weight:bold;';
					}else{
						$backup_url = '#';
						$backup_title = '';
						$backup_error_style = '';
					}
				}
				
				$std_value->file = preg_replace('/.(jpg|jpeg|png|gif)$/','.webp', $std_value->file);
				
				if(file_exists($std_value->file)){
					$std_value->url = preg_replace('/.(jpg|jpeg|png|gif)$/','.webp', $std_value->url).'?v='.time();
				}else{
					$std_value->url = SPEEDYCACHE_PRO_URL.'/assets/images/no-image.png';
				}

				$short_code = array(
					'{{post_id}}',
					'{{attachment}}',
					'{{post_title}}',
					'{{url}}',
					'{{width}}',
					'{{height}}',
					'{{reduction}}',
					'{{date}}',
					'{{revert_button}}',
					'{{backup_url}}',
					'{{backup_title}}',
					'{{backup_error_style}}'
				);
				
				$datas = array(
					$std_value->id,
					$std_value->url,
					$post->post_title,
					$std_value->url,
					$std_value->width,
					$std_value->height,
					$std_value->reduction/1000,
					date('d-m-Y <br> H:i:s', $std_value->time),
					$revert_button,
					$backup_url,
					$backup_title,
					$backup_error_style
				);
			
				$return_output .= str_replace($short_code, $datas, $content);
			}
		}
		return $return_output;
	}

	static function allowed_mime($filename){
		global $speedycache;
		
		$mimetype = false;

		if(!file_exists($filename)){
			return false;
		}

		if(function_exists('finfo_open')){
		   $finfo = finfo_open(FILEINFO_MIME_TYPE);
		   $mimetype = finfo_file($finfo, $filename);
		   finfo_close($finfo);
		}else if(function_exists('getimagesize')){
		   $img = getimagesize($filename);
		   $mimetype = $img['mime'];
		}else{
			echo 'not found mime_content_type';
			exit;
		}
		
		if($speedycache->image['settings']['compression_method'] === 'cwebp' && self::gif2webp_exists()){
			if(preg_match('/(jpg|jpeg|jpe|png|gif)/i', $mimetype)){
				return true;
			}
			
			return false;
		}

		if(preg_match('/(jpg|jpeg|jpe|png)/i', $mimetype)){
			return true;
		}
		
		return false;
	}

	// Check if the image is available, the response code should be 200
	static function not_found($url){
		return false;
		
		$res = wp_remote_head($url, array('timeout' => 3 ));

		if(is_wp_error($res)){
			$url_header = @get_headers($url);

			if(preg_match('/200\s+OK/i', $url_header[0])){
				return false;
			}
			
			return true;
		}
		
		if($res['response']['code'] == 200){
			return false;
		}

		return true;
	}

	//Checks if the image is Unique
	static function unique_array($images){
		if(count($images) <= 1){
			return $images;
		}

		$arr = array();
		$images_tmp = array();

		foreach($images as $key => $value){
			if(!in_array($value['file'], $arr)){
				array_push($arr, $value['file']);
				array_push($images_tmp, $value);
			}
		}
		
		return $images_tmp;
	}
	//Template static functions Starts Here

	//Table row for the converted Image
	static function get_row(){
		return '<tr class="alternate author-self status-inherit" post-id="{{post_id}}">
			<td class="column-icon media-icon image-icon">
				<img width="39" height="60" src="{{attachment}}" class="attachment-80x60">
			</td>
			<td class="title column-title">
				<p style="margin-bottom: 0;"><a href="{{url}}" target="_blank">{{post_title}}</a></p>
				<p style="margin-bottom: 0;">
					<a style="{{backup_error_style}}" href="{{backup_url}}" target="_blank"><strong>{{backup_title}}</strong></a>
				</p>
			</td>
			<td class="author column-author speedycache-open-image-details" style="text-align: center;cursor: pointer;">{{reduction}}KB<span class="dashicons dashicons-arrow-down-alt2"></span></td>
			<td class="date column-date" style="text-align: center;">{{date}}</td>
			<td class="date column-date" style="text-align: center;">
			<div class="speedycache-revert" style="{{revert_button}}">
				<input type="hidden" value="{{post_id}}">
			</div>
			</td>
		</tr>';
	}

	//table row for different sizes of image.
	static function get_child_row(){
		
		return '<tr class="alternate author-self status-inherit" post-id="{{post_id}}" post-type="detail" style="display: none; padding-left: 20px;">
			<td class="column-icon media-icon" style="font-size:3.5em; color:#ccc;"><i class="fas fa-image"></i></td>
			<td class="title column-title">
				<p style="margin-bottom: 0;"><a href="{{url}}" target="_blank">{{post_title}}</a></p>
				<p style="margin-bottom: 0;">
					<a style="{{backup_error_style}}" href="{{backup_url}}" target="_blank"><strong>{{backup_title}}</strong></a>
				</p>
				<p style="margin-bottom: 0;">{{width}}x{{height}}</p>
			</td>
			<td class="author column-author" style="text-align: center;">{{reduction}}KB</td>
			<td class="date column-date" style="text-align: center;">{{date}}</td>
			<td class="date column-date" style="text-align: center;">
			</td>
		</tr>';
	}

	//No Image optimized
	static function get_empty_row(){
		return '<tr class="author-self status-inherit">
			<td colspan="4">No image has been optimized yet</td>
		</tr>';

	}

	//Paging for the converted Images Table
	static function paging(){ ?>
		<div class="tablenav bottom" style="padding:5px 16px 5px 19px">
			<div style="float:left;">
				<span class="deleteicon">
					<input type="text" style="height:28px;" placeholder="Search" id="speedycache-image-search-input" class="deletable" value="">
					<span class="cleared"></span>
				</span>
				<input type="submit" class="button action" value="Search" id="speedycache-image-search-button" name="filter_action">
			</div>
			<div style="float:left;padding-left:5px;">
				<select id="speedycache-image-list-filter" class="bulk-action-selector-top">
					<option value="" selected="selected">All</option>
					<option value='error_code'>Errors</option>
				</select>
			</div>
			<div style="float:left;padding-left:5px;">
				<select id="speedycache-image-per-page" class="bulk-action-selector-top">
					<option value="5" selected="selected">5</option>
					<option value="10">10</option>
					<option value="25">25</option>
				</select>
			</div>
			<div class="tablenav-pages">
				<span class="pagination-links">
					<a class="tablenav-pages-navspan button first-page disabled speedycache-image-list-first-page" aria-hidden="true" data-page-action="first-page">«</a>
					<a class="tablenav-pages-navspan button prev-page speedycache-image-list-prev-page" aria-hidden="true" data-page-action="prev-page">‹</a>
					<a class="paging-input"><label class="speedycache-current-page">1</label> / <span class="total-pages speedycache-total-pages">1</span></a>
					<a class="next-page button speedycache-image-list-next-page" data-page-action="next-page">›</a>
					<a class="last-page button speedycache-image-list-last-page" data-page-action="last-page">»</a>
				</span>
			</div>
			<br class="clear">
		</div>
	<?php
	}

	//Settings for Image Optimization
	static function settings(){
		global $speedycache, $speedycache_optm_method; 

		?>
		<div class="speedycache-block">
			<div class="speedycache-block-title"><h2><?php _e('Settings', 'speedycache'); ?></h2></div>
			<form class="speedycache-img-opt-settings">
				<div class="speedycache-option-wrap">
					<label for="speedycache_img_automatic_optm" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_img_automatic_optm" name="img_automatic_optm" <?php echo (isset($speedycache->image['settings']['automatic_optm']) && $speedycache->image['settings']['automatic_optm']) ? ' checked="true"' : '';?>/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name"><?php esc_html_e('Automatic optimization', 'speedycache'); ?></span>
						<span class="speedycache-option-desc"><?php esc_html_e('Whenever user visits the website and there are images that haven\'t been converted to webp then that image(s) gets converted.', 'speedycache'); ?></span>
					</div>
				</div>
				<div class="speedycache-option-wrap">
					<label for="speedycache_img_on_upload" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_img_on_upload" name="img_on_upload" <?php echo (isset($speedycache->image['settings']['on_upload']) && $speedycache->image['settings']['on_upload']) ? ' checked="true"' : '';?>/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name"><?php esc_html_e('Optimize on Image Upload', 'speedycache'); ?></span>
						<span class="speedycache-option-desc"><?php esc_html_e('Images will be added to a queue and will optimized after a certain interval to reduce load on the server.', 'speedycache'); ?></span>
					</div>
				</div>
				
				<div class="speedycache-option-wrap">
					<label for="speedycache_img_url_rewrite" class="speedycache-custom-checkbox">
						<input type="checkbox" id="speedycache_img_url_rewrite" name="img_url_rewrite" <?php echo (isset($speedycache->image['settings']['url_rewrite']) && $speedycache->image['settings']['url_rewrite']) ? ' checked="true"' : '';?>/>
						<div class="speedycache-input-slider"></div>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name"><?php esc_html_e('Rewrite Image URL\'s', 'speedycache'); ?></span>
						<span class="speedycache-option-desc"><?php esc_html_e('Rewrites the url of the image on the page to the webp version if webp version is avaliable.', 'speedycache'); ?></span>
					</div>
				</div>

				<div class="speedycache-option-wrap">
					<label for="speedycache_img_quality">
						<input type="number" id="speedycache_img_quality" name="img_compression_quality" value="<?php echo esc_attr($speedycache->image['settings']['compression_quality']);?>" min="50" step="5" max="90"/>
					</label>
					<div class="speedycache-option-info">
						<span class="speedycache-option-name"><?php esc_html_e('Compression Quality', 'speedycache'); ?></span>
						<span class="speedycache-option-desc"><?php esc_html_e('Higher the number higher will be the converted image quality in webp', 'speedycache'); ?></span>
					</div>
				</div>
				
				<div class="speedycache-block-title" style="flex-direction:column">
					<h4><?php esc_html_e('Conversion Methods', 'speedycache'); ?></h4>
					<p style="display:block; font-family: monospace; background-color: #f2f2f2; border-radius:6px; padding:10px;"><span style="color:var(--speedycache-red); font-weight:bold;"><i class="fas fa-exclamation"></i> Note:</span><?php esc_html_e('Only cwebp supports gif conversions to webp. But when you upload an image to WordPress whether it be a jpg, png, or gif format, WordPress creates different sizes of that image on upload so, in the process of resizing some resized version of gifs may lose their animation.', 'speedycache'); ?>
				</div>
				<?php foreach($speedycache_optm_method as $m_key => $method){ ?>
					<div class="speedycache-option-wrap <?php echo !$method['status'] ? ' speedycache-disabled-methods' : '' ?>">
						<label for="speedycache-img-<?php echo esc_attr($m_key);?>">
							<input type="radio" value="<?php echo esc_attr($m_key);?>" name="img_compression_method" id="speedycache-img-<?php echo esc_attr($m_key);?>" <?php echo (isset($speedycache->image['settings']['compression_method']) && $speedycache->image['settings']['compression_method'] == $m_key ? ' checked="true"' : '');?> <?php echo !$method['status'] ? ' disabled' : '' ?>/>
						</label>
						<div class="speedycache-option-info">
							<span class="speedycache-option-name"><?php echo esc_html($method['title']); ?></span>
							<span class="speedycache-option-desc"><?php echo esc_html($method['desc']); ?></span>
						</div>
						<?php 
						// TODO:: Need to fix this _e as it is a dynamic value we will need to use sprintf
						if(!$speedycache_optm_method[$m_key]['status']){ ?>
							<div class="speedycache-more-info" data-info="<?php echo esc_html($speedycache_optm_method[$m_key]['message']);?>" >
								<i class="fas fa-question-circle"></i>
							</div>
						<?php } ?>
							<div class="speedycache-img-method-actions">
						<?php 
						
						if($m_key == 'cwebp'){
							if(defined('SPEEDYCACHE_PRO') && !file_exists(wp_upload_dir()['basedir']. '/speedycache-binary/'.$speedycache->image['cwebp_binary'])){
								echo '<button style="margin-right:5px;" class="speedycache-button speedycache-btn-black speedycache-webp-download">Download Binary</button>';
							}
							
							if(defined('SPEEDYCACHE_PRO') && !self::gif2webp_exists()){
								echo '<button class="speedycache-button speedycache-btn-black speedycache-webp-download" style="margin-top:2px;" data-type="gif">Download Binary for GIF</button>';
							}
						}
						?>
						</div>
					</div>	
				<?php } ?>
			</form>
		</div>
	<?php 
	}


	//Image Optimization Stats
	static function statics(){
		$res = self::statics_data();
		$ring_success = 100 - (int)$res['percent'];
		
		$scheduled = self::get_optimization_schedule(array('speedycache_auto_optm', 'speedycache_img_delete'));
		$scheduled_count = count($scheduled);
		
		//the css below is written in one line to make regex replace easy in js update.
	?>
		<style>
			@keyframes donut1 {
			0%{stroke-dasharray: 0, 100;}
			100%{stroke-dasharray: <?php echo esc_attr($res['percent'] .', ' . $ring_success);?>;}
		}
		</style>
		<div class="speedycache-block">
			<div class="speedycache-img-stats speedycache-admin-row">
				<div class="speedycache-is-block speedycache-img-graph">
					<div class="speedycache-card-body">
						<div class="speedycache-img-start-optm">
							<div class="speedycache-img-stat-info">
								<div class="speedycache-img-main-stat">
									<?php esc_html_e('Success', 'speedycache'); ?>
									<span class="speedycache-img-success-per"><?php echo esc_html($res['percent']);?>%</span>
								</div>
								<div class="speedycache-img-main-stat">
									<?php esc_html_e('Error', 'speedycache');?>
									<span class="speedycache-img-error-count" <?php echo $res['error'] > 0 ? 'style="color:#dc3545"' : '' ?>><?php echo esc_html($res['error']);?></span>
								</div>
								<div class="speedycache-img-main-stat">
									<?php esc_html_e('Scheduled', 'speedycache');?>
									<span class="speedycache-scheduled-count <?php echo $scheduled_count > 0 ? 'speedycache-scheduled-count-indicator' : '';?>" setting-id="speedycache-img-scheduled-modal"><?php echo esc_html($scheduled_count);?></span>
								</div>
							</div>
							<div class="speedycache-img-remain-optm">
								<span class="speedycache_img_optm_status" style="background-color:<?php echo $res['uncompressed'] > 0 ? '#EED202' : '#90ee90'?>"></span>
								<span>
								<?php 
									if($res['uncompressed'] > 0){
										echo esc_html($res['uncompressed']) . ' ';
										esc_html_e('Files needed to be optimized', 'speedycache');
									} else {
										esc_html_e('All images are optimized', 'speedycache');
									}	
								?></span>
									
							</div>
							<div class="speedycache-img-optimize-all" style="margin-left:auto;">
								<button class="speedycache-button speedycache-btn-black speedycache-img-optm-btn" setting-id="speedycache-modal-optimize-all"><?php esc_html_e('Optimize All', 'speedycache'); ?></button>
								<button class="speedycache-img-delete-all-conv speedycache-button speedycache-btn-transparent"><?php esc_html_e('Delete all conversions', 'speedycache'); ?></button>
							</div>
						</div>
					</div>
				</div>
		
				<div class="speedycache-is-block speedycache-img-count">
					<div>
						<div class="speedycache-img-opt-stat">
							<div class="speedycache-img-optm-count"><?php echo esc_html($res['optimized'] . '/' . $res['total_image_number']); ?></div>
							<div class="speedycache-img-optm-count-text"><?php echo esc_html_e('Image(s) optimized', 'speedycache'); ?>
							<?php echo esc_html_e('with total reduction of', 'speedycache'); ?> <span class="speedycache-img-reduced-size"><?php echo esc_html($res['reduction'] > 10000 ? round($res['reduction']/1000, 2).'MB' : $res['reduction'].'KB');?></span></div>
						</div>
					</div>
				</div>
			</div>
		</div>
		
		<div modal-id="speedycache-img-scheduled-modal" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div><?php esc_html_e('Scheduled Tasks', 'speedycache'); ?></div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content speedycache-info-modal">
					<?php if($scheduled_count < 1){ ?>
						<span><?php esc_html_e('No Image Scheduled', 'speedycache'); ?></span>
					<?php } else { ?>
					<!--<p style="text-align:center;"><?php //_e('Time Interval of the Schedule is 1 minute', 'speedycache');?></p>-->
					<table style="margin:auto; width: 100%;">
						<thead>
							<tr>
								<th class="speedycache-table-hitem" scope="col"><?php esc_html_e('Image', 'speedycache'); ?></th>
								<th class="speedycache-table-hitem" scope="col"><?php esc_html_e('Time', 'speedycache'); ?></th>
							</tr>
						</thead>
						<tbody>
							<?php
							foreach($scheduled as $key => $schedule){

								$time = $schedule['time'] - time();

								$time_str = 'in '.$time. ' seconds';
								
								if($time > 59){
									$time_str = 'in '. round($time/60, 1) . ' minute(s)';
								} else if($time <= 0){
									$time_str = 'now';
								}
								?>
							<tr>
								<td class="speedycache-table-item"><?php echo esc_html('Batch ' . ($key + 1)); ?></td>
								<td class="speedycache-table-item" style="text-align:right;"><?php echo esc_html($time_str);?> <i class="fas fa-stopwatch"></i></td>
							</tr>
							<?php } ?>
							
						</tbody>
					</table>
					<?php } ?>
				</div>
			</div>
		</div>
		
		<div modal-id="speedycache-modal-all-img-revert" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-content">
					<i class="fas fa-info-circle"></i>
					<h1><?php esc_html_e('Revert All Images!', 'speedycache'); ?></h1>
					<p><?php esc_html_e('Once deleted the changes won\'t be reversible.', 'speedycache'); ?></p>
					<div class="speedycache-modal-db-actions">
						<button class="speedycache-btn speedycache-db-confirm-yes"><?php esc_html_e('Yes', 'speedycache'); ?></button>
						<button class="speedycache-btn speedycache-db-confirm-no"><?php esc_html_e('No', 'speedycache'); ?></button>
					</div>
				</div>
			</div>
		</div>
	<?php
	}
	//Templates Ends here

	//Need to create logs for Automatic Optimization
	static function log(){
		
	}

	static function compression_method_checks(){
		global $speedycache, $speedycache_optm_method;
		
		$gd = self::gd_check();
		$speedycache_optm_method['gd'] = array_merge($speedycache_optm_method['gd'], $gd);
		
		if(!$speedycache_optm_method['gd']['status']){
			$speedycache->image['disabled_method']++;
			self::change_method_if_not_available('gd');
		}
		
		$imagick = self::imagick_check();
		$speedycache_optm_method['imagick'] = array_merge($speedycache_optm_method['imagick'], $imagick);
		
		if(!$speedycache_optm_method['imagick']['status']){
			$speedycache->image['disabled_method']++;
			self::change_method_if_not_available('imagick');
		}
		
		$cwebp = self::cwebp_check();
		$speedycache_optm_method['cwebp'] = array_merge($speedycache_optm_method['cwebp'], $cwebp);
		
		if(!$speedycache_optm_method['cwebp']['status']){
			$speedycache->image['disabled_method']++;
			self::change_method_if_not_available('cwebp');
		}
	}

	// GD static function Starts here
	static function gd_check(){
		if(!extension_loaded('gd')){
			return array('status' => false, 'message' => 'You dont have GD PHP extension');
		}

		if(isset(gd_info()['WebP Support']) && !gd_info()['WebP Support']){
			return array('status' => false, 'message' => 'GD extension on your server dosen\'t support WEBP');
		}
		
		if(isset(gd_info()['WebP Support']) && gd_info()['WebP Support']){
			return array('status' => true, 'message' => 'Operational');
		}
	}

	static function gd_webp($file){
		global $speedycache, $speedycache_optm_method;

		if(isset($speedycache_optm_method['gd']['status']) && !$speedycache_optm_method['gd']['status']){
			return array('success' => false, 'error_message' => $speedycache_optm_method['gd']['message']);
		}
		
		$image_size = getimagesize($file);
		$width = $image_size[0];
		$height = $image_size[1];
		
		switch($image_size['mime']){
			case 'image/jpg':
			case 'image/jpeg':
				$source = imagecreatefromjpeg($file);
				break;
			
			case 'image/png':
				$source = imagecreatefrompng($file);
				break;
				
			case 'image/webp': 
				return array('success' => false, 'error_message' => 'File is alredy a WEBP file');
				
			default:
				return array('success' => false, 'error_message' => 'File has unsupported mime'.$image_size['mime']);
		}
		
		if(empty($source)){
			return false;
		}
		
		$dst = imagecreatetruecolor($width, $height);
		
		if(imagealphablending($dst, false) !== false){
			//change the RGB values if you need, but leave alpha at 127
			$transparent = imagecolorallocatealpha($dst, 255, 255, 255, 127);

			if($transparent !== false){
				//simpler than flood fill
				if(imagefilledrectangle($dst, 0, 0, $width, $height, $transparent) !== false){
					//restore default blending
					if(imagealphablending($dst, true) !== false){
						if(imagecopy($dst, $source, 0, 0, 0, 0, $width, $height) !== false){
							$success = true;
						}
					};
				}
			}
		}
		
		if(!$success){
			return array('success' => false, 'error_message' => 'Couldn\'t convert the given image.');
		}
		
		$webp_path = preg_replace('/.(jpe?g|png)$/', '.webp', $file);
		
		imagedestroy($source);
		imagewebp($dst, $webp_path, $speedycache->image['settings']['compression_quality']);
		imagedestroy($dst);
		
		if(!file_exists($webp_path)){
			return array('url' => $webp_path, 'success' => true, 'error_message' => 19);
		}

		return array(
			'url' => $webp_path,
			'success' => true,
			'error_message' => ''
		);
	}
	//GD Ends Here

	//Imagick static functions
	static function imagick_check(){
		
		if(!extension_loaded('imagick')){
			return array('status' => false, 'message' => 'Imagick extension isn\'t installed');
		}
		
		$image = new \Imagick();
		
		if(!in_array('WEBP', $image->queryFormats('WEBP'))){
			$image->clear();
			$image->destroy();
		
			return array('status' => false, 'message' => 'Imagick installed on your system is without WEBP support');
		}
		
		return array('status' => true, 'message' => 'Operational');
	}

	static function change_method_if_not_available($m_name){
		global $speedycache, $speedycache_optm_method;
		
		if($speedycache->image['settings']['compression_method'] != $m_name){
			return;
		}
		
		$valid_method = '';
		
		foreach($speedycache_optm_method as $key => $method){
			if($key == $m_name){
				continue;
			}
			
			if(!empty($method['status'])){
				$speedycache->image['settings']['compression_method'] = $key;
				return;
			}
		}

		$speedycache->image['settings']['compression_method'] = $valid_method;
	}

	//Conversion of image to webp
	static function imagick_webp($file){
		global $speedycache, $speedycache_optm_method;
		
		if(isset($speedycache_optm_method['imagick']['status']) && !$speedycache_optm_method['imagick']['status']){
			return array('success' => false, 'error_message' => $speedycache_optm_method['imagick']['message']);
		}
		
		$dest = preg_replace('/.(png|jpe?g)$/', '.webp', $file);
		
		$image = new \Imagick();
		$image->readImage($file);
		$image->setImageCompressionQuality($speedycache->image['settings']['compression_quality']);
		$image->setImageFormat('WEBP');
		
		if($image->writeImage($dest)){
			$image->clear();
			$image->destroy();
			
			return array('success' => true, 'error_message' => '');
		}
		
		$image->clear();
		$image->destroy();
		
		return array('success' => false, 'error_message' => 'File didn\'t got saved');
	}

	//cwebp static functions
	static function cwebp_check(){
		global $speedycache;
		
		if(!defined('SPEEDYCACHE_PRO')){
			return array('status' => false, 'message' => 'cwebp is a SPEEDYCACHE PRO feature.');
		}
		
		if(!function_exists('exec')){
			return array('status' => false, 'message' => 'You dont have access to exec static function hence you cant use cWebP for Image optimizations');
		}
		
		if(isset($speedycache->image['cwebp_binary'])){
			
			if(!file_exists(wp_upload_dir()['basedir'].'/speedycache-binary/'.$speedycache->image['cwebp_binary'])){
				return array('status' => false, 'message' => 'You don\'t have the cwebp Binary on your server.', 'downloaded' => false);
			} 
		}
		
		return array('status' => true, 'message' => 'Operational');
	}

	static function rewrite_url_to_webp($content){
		if(strpos(speedycache_optserver('HTTP_ACCEPT'), 'image/webp') < 0){
			return $content;
		}
		
		if( ! preg_match_all( '/<img\s[^>]+>/', $content, $matches, PREG_SET_ORDER ) ){
			return $content;
		}
		
		foreach($matches as $match){
			///(?i)(https?:\/\/|www.|\w+\.(png|jpe?g)$)[^\s]+/
			preg_match_all('/https?:\/(\/[^\/]+)+\.(?:jpe?g|png|gif)/', $match[0], $urls, PREG_SET_ORDER); 
			
			foreach($urls as $url){
				$file_url = preg_replace('/.(jpe?g|png|gif)$/', '.webp', $url[0]);
				
				$file_path = explode(SPEEDYCACHE_WP_CONTENT_DIR.'/uploads', $file_url);

				if(!isset($file_path[1]) || !file_exists(wp_upload_dir()['basedir'].$file_path[1])){
					continue;
				}
				
				$content = str_replace($url[0], $file_url, $content);
			}
		
		}
		
		return $content;
	}

	//Adding wp event for automatic optm on image upload
	static function convert_on_upload($id){
		global $speedycache;

		if(!$speedycache->image['settings']['on_upload']){
			return;
		}
		
		if(!wp_attachment_is_image($id)){
			return;
		}
		
		$scheduled = self::get_optimization_schedule(array('speedycache_auto_optm'));
		$time = time();
		
		if(!empty($scheduled) && isset(end($scheduled)['time'])){
			$time = end($scheduled)['time'];
		}
		
		// Convert after 5 minutes of upload
		if(!wp_next_scheduled('speedycache_auto_optm', array($id))){
			wp_schedule_single_event($time + 300, 'speedycache_auto_optm', array($id));
			return;
		}
	}

	//Optimizing image on Upload
	static function auto_optimize($img_id){
		self::optimize_single($img_id);
	}

	//Whenever user visits a page and there are images that dont have a webp versions then those images are set to be converted.
	static function optimize_on_fly($content){
		global $wpdb, $speedycache;

		//Sitepad dosen't have this static function.
		if(function_exists('wp_filter_content_tags')){
			$content = wp_filter_content_tags($content);
		}

		if(!preg_match_all('/<img\s[^>]+>|background:\s*url\(["\']?(.*?)["\']?\)/i', $content, $matches, PREG_SET_ORDER)){
			return $content;
		}

		foreach($matches as $match){
			// pl-image{post-id} will work only after Pagelayer 1.9.0
			if(!preg_match('/(?:wp|pl)-image-([\d]+)/i', $match[0], $post_id)){
				/*
				* This is for compatibility with other editors and for inline css background url
				* what we do here is look for either img src url or background:url()
				* Then we attempt to get id from the URL.
				*/
				//<img(?:[^>]|[^\/>]).*src[\s*]?=[\s*]?"(.+?)" just in case the one used causes bugs
				if(strpos($match[0], 'background:url') === FALSE && !preg_match('/<img.*?src="(.*?)"/', $match[0], $url)){
					continue;
				}
				
				if(strpos($match[0], 'background:url') !== FALSE){
					$image_url = sanitize_url($match[1]);
				} else {
					$image_url = sanitize_url($url[1]);
				}

				$post_id = (int) attachment_url_to_postid($image_url);
				
				if(empty($post_id)){
					$file = basename($image_url);
					$like = '%'.$wpdb->esc_like($file) .'%';
					$query = $wpdb->prepare("SELECT `post_id` FROM `".$wpdb->prefix."postmeta` WHERE `meta_value` LIKE %s", $like);
					$post_id = (int) $wpdb->get_var($query);
				}

				if(empty($post_id)){
					continue;
				}
			}
		
			if(empty($post_id)){
				continue;
			}
			
			// If we captured post id through wp-image|pl-image
			if(is_array($post_id) && isset($post_id[1])){
				$post_id = intval($post_id[1]);
			}

			// If the image is already scheduled for optimization then just skip it.
			if(wp_next_scheduled('speedycache_auto_optm', array($post_id))){
				continue;
			}
			
			if(!get_post($post_id)){
				continue;
			}

			$optimized = (int) $wpdb->get_var($wpdb->prepare("SELECT count(`meta_key`) as optimized FROM `".$wpdb->prefix."postmeta` WHERE `meta_key`= 'speedycache_optimisation' AND `post_id`=%d", $post_id));
			
			if($optimized > 0){
				continue;
			}
			
			$scheduled = self::get_optimization_schedule(array('speedycache_auto_optm'));
			$time = time();
		
			if(!empty($scheduled) && isset(end($scheduled)['time'])){
				// getting the last index to get the last scheduled event
				$time = end($scheduled)['time'];
			}
			
			$final_schd_time = $time + 60;
		
			if(!wp_next_scheduled('speedycache_auto_optm', array($post_id))){
				wp_schedule_single_event($final_schd_time, 'speedycache_auto_optm', array($post_id));
				
				continue;
			}
		}

		return $content;
	}

	// Returns an array of cron event "speedycache_auto_optm"
	static function get_optimization_schedule($event_name){
		$cron = _get_cron_array();
		
		if(empty($cron)){
			return false;
		}
		
		$scheduled = array();
		
		foreach($cron as $key => $crn){
			foreach($crn as $e_key => $event){
				if(!in_array($e_key, $event_name)){
					continue;
				}

				foreach($event as $evt){
					$args = $evt['args'][0];
				}
				
				array_push($scheduled, array('name' => get_the_title($args), 'time' => $key));
			}
		}
		
		return $scheduled;
	}

	static function gif2webp_exists(){
		global $speedycache;
		
		if(file_exists(wp_upload_dir()['basedir']. '/speedycache-binary/'.$speedycache->image['cwebp_gif'])){
			return true;
		}
		
		return false;
	}
	
	static function download_cwebp(){
		global $speedycache;

		check_ajax_referer('speedycache_ajax_nonce', 'security');
		
		$binary_name = $speedycache->image['cwebp_binary'];
		
		$type = speedycache_optget('type');
		
		switch($type){
			case 'gif':
				$binary_name = $speedycache->image['cwebp_gif'];
				break;
				
			case 'cwebp':
				$binary_name = $speedycache->image['cwebp_binary'];
				break;
				
			default:
				return;
		}
		
		$binary_path = wp_upload_dir()['basedir'].'/speedycache-binary';
		
		if(!file_exists($binary_path)){
			@mkdir($binary_path);
		}
		
		//If The binary alredy exists on the server
		if(file_exists($binary_path.'/'.$binary_name)){
			wp_send_json(array('success' => false, 'error_message' => 'Binary Exists already.'));
		}
		
		$resp = wp_remote_get(SPEEDYCACHE_API.'/files/cwebp/'.$binary_name);
		$json = wp_remote_get(SPEEDYCACHE_API.'/files/hash.json');
		
		$hash = json_decode($json['body'], true);
		$file = $resp['body'];
		
		if(!$hash){
			wp_send_json(array('success' => false, 'error_message' => 'Unable to verify the downloaded binary.'));
		}
		
		if(!$file){
			wp_send_json(array('success' => false, 'error_message' => 'Could not download the file please try again later.'));
		}
		
		$binary_file = $binary_path.'/'.$binary_name;
		
		file_put_contents($binary_file, $file);
		
		if(!file_exists($binary_file)){
			wp_send_json(array('success' => false, 'error_message' => 'There was issue downloading the binary.'));
		}
		
		if(hash_file('md5', $binary_file) != $hash[$binary_name]){
			@unlink($binary_path.'/'.$binary_name);
			wp_send_json(array('success' => false, 'error_message' => 'Hash of the file downloaded didn\'t match'));
		}
			
		@chmod($binary_file, 0755);
		
		$output = null;
		$res = null;
		
		if(!function_exists('exec')){
			wp_send_json(array('success' => false, 'error_message' => 'Your server dosen\'t supports exec'));
		}
		
		$exec_name = $type === 'gif' ? 'gf2webp' : 'cwebp';
		
		/*
		* To check if the binary is supported by the server.
		*/
		exec('"'.$binary_file.'"  '.$exec_name.' -version 2>&1', $output, $res);
		
		if($res != 0){
			wp_send_json(array('success' => false, 'error_messsage' => 'The binary for cwebp isn\'t supported by your server'));
		}
		
		if($type = 'gif'){
			$speedycache->image['cwebp_gif'] = $binary_name;
		} else {
			$speedycache->image['cwebp_binary'] = $binary_name;
		}
		
		wp_send_json(array('success' => true));
	}

	static function cwebp_convert($file){
		global $speedycache, $speedycache_optm_method;
		
		if(isset($speedycache_optm_method['cwebp']['status']) && !$speedycache_optm_method['cwebp']['status']){
			return array('success' => false, 'error_message' => $speedycache_optm_method['cwebp']['message']);
		}
			
		$mime = mime_content_type($file);
		
		if($mime == 'image/gif'){
			$binary_path = wp_upload_dir()['basedir']. '/speedycache-binary/'.$speedycache->image['cwebp_gif'];
			$binary_name = 'gif2webp';
		} else {
			$binary_path = wp_upload_dir()['basedir']. '/speedycache-binary/'.$speedycache->image['cwebp_binary'];
			$binary_name = 'cwebp';
		}
		
		$output_file = preg_replace('/.(jpe?g|png|gif)$/', '.webp', $file);
		

		$res = null;
		$output = null;
		
		if(!file_exists($binary_path)){
			return array('success' => false, 'error_message' => 'The binary to use cwebp not found');
		}
		
		/*
		*	-- Use "" around the paths in exec, as without "" can cause a bug on some servers installs. 
		*	-- The Structure of the command below is :- 
		*	"path_of_binary" cwebp -q [quality_in_int] "original_file_path" -o "output_file.webp"
		*	-- 2>&1 is used to redirect stderr to same place as stdout
		*	https://www.brianstorti.com/understanding-shell-script-idiom-redirect/
		*/
		exec('"'.$binary_path.'" '.$binary_name.' -q '.$speedycache->image['settings']['compression_quality'].' "'.$file. '" -o "'. $output_file. '" 2>&1', $output, $res);
		
		if($res != 0){
			return array('success' => false, 'error_message' => 'Couldn\'t convert the given image using cwebp.', 'error_code' => 22);
		}
		
		return array('success' => true, 'error_message' => '', 'dest' => $output_file);
	}
	
	static function list_image_html(){
	?>
	<div id="speedycache-image-list">
		<?php \SpeedyCache\Image::paging(); ?>
		<div style="width:100%; overflow-x:auto;">
			<table class="wp-list-table widefat fixed media" style="width: 95%; margin-left: 20px;">
				<thead>
					<tr style="height: 35px;">
						<th scope="col" id="icon" class="manage-column column-icon" style=""></th>
						<th scope="col" id="title" class="manage-column column-title sortable desc" style="width: 323px;">
							<span style="padding-left: 8px;"><?php esc_html_e('File Name', 'speedycache'); ?></span>
						</th>
						<th scope="col" id="author" class="manage-column column-author sortable desc" style="width: 120px;text-align: center;">
							<span><?php esc_html_e('Reduction', 'speedycache'); ?></span>
						</th>
						<th scope="col" id="date" class="manage-column column-date sortable asc" style="width: 91px;text-align: center;">
							<span><?php esc_html_e('Date', 'speedycache'); ?></span>
						</th>
						<th scope="col" id="date" class="manage-column column-date sortable asc" style="width: 60px;text-align: center;">
							<span><?php esc_html_e('Revert', 'speedycache'); ?></span>
						</th>	
					</tr>
				</thead>
				<tbody id="the-list">
					<?php 
						$query_images_args = array();

						$query_images_args['order'] = 'DESC';
						$query_images_args['orderby'] = 'ID';
						$query_images_args['post_type'] = 'attachment';
						$query_images_args['post_mime_type'] = array('image/jpeg', 'image/png', 'image/gif');
						$query_images_args['post_status'] = 'inherit';
						$query_images_args['posts_per_page'] = 5;
						$query_images_args['meta_query'] = array(
							array(
								'key' => 'speedycache_optimisation',
								'compare' => 'EXISTS'
							)
						);

						echo \SpeedyCache\Image::list_content($query_images_args);
					?>
				</tbody>
			</table>
		</div>
	</div>
	<?php 
	}

}

index.html000064400000000133151526435070006546 0ustar00<h1>Powered By SpeedyCache</h1>
Go to <a href="https://speedycache.com">SpeedyCache.Com</a>criticalcss.php000064400000022373151526435070007577 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt');
}

class CriticalCss extends CommonCss{

	static function generate($urls){
		global $speedycache;

		$time = time() + 50;
		set_time_limit(60);
		
		$api = self::get_endpoint();
		
		if(empty($urls)){
			self::log('speedycache_ccss_logs', 'URL not found');
			return false;
		}

		if(empty($speedycache->license['license'])){
			self::log('speedycache_ccss_logs', 'License Not found, please link your License');
			return false;
		}

		$path = speedycache_cache_path('critical-css/');
		$error = ''; // To hold errors when single Critical CSS is generated
		$attempted_url = []; // Keeping track of URL that have been proccessed to generate CriticalCSS to handle in case of Timeout

		if(!is_dir($path)){
			mkdir($path);
			touch($path . 'index.html');
		}

		foreach($urls as $url){
			// Handeling php timeout here
			if($time < time()){
				$urls = array_diff($urls, $attempted_url);
				self::schedule($urls);
				return;
			}

			$url = trim($url, '/');
			$license = strpos($speedycache->license['license'], 'SPDFY') !== 0 ? '' : $speedycache->license['license'];
			$attempted_url[] = $url;

			$basename = md5($url);
			$file_name = $path . $basename . '.css';

			$response = wp_remote_post($api, array(
				'timeout' => 30,
				'body' => array(
					'url' => $url,
					'license' => $license,
				),
				'sslverify' => false,
			));

			if(is_wp_error($response)){
				$error = $response->get_error_message();
				self::log('speedycache_ccss_logs', $response->get_error_message(), $url);
				continue;
			}

			$body = json_decode(wp_remote_retrieve_body($response), true);
			
			if(empty($body)){
				$error = __('The response recieved is empty.', 'speedycache');
				self::log('speedycache_ccss_logs', __('The response recieved is empty.', 'speedycache'), $url);
				continue;
			}

			if(empty($body['success'])){
				$error = !empty($body['message']) ? wp_strip_all_tags($body['message']) : __('Unable to extract CriticalCss', 'speedycache');
				self::log('speedycache_ccss_logs', !empty($body['message']) ? wp_strip_all_tags($body['message']) : __('Unable to extract CriticalCss', 'speedycache'), $url);
				continue;
			}

			if(empty($body['css']) || strlen($body['css']) < 20){
				$error = __('Was unable to generate Critical CSS', 'speedycache');
				self::log('speedycache_ccss_logs', __('Was unable to generate Critical CSS', 'speedycache'), $url);
				continue;
			}
			
			if(!is_dir($path)){
				mkdir($path);
			}
			
			file_put_contents($file_name, $body['css']);

			self::update_css($url, $body['css']);
			
			self::log('speedycache_ccss_logs', 'success', $url); //Updates the log on success
			
			if(!empty($error)){
				return $error;
			}

			return true;
		}
	}
	
	// Builds up the list to schedule URLs
	static function get_url_list(){
		global $blog_id;
		
		$pages = get_pages(array('child_of' => 0, 'number' => 9));
		
		if(empty($pages)){
			return false;
		}

		$page_to_crawl = [];

		$url = get_home_url(!empty($blog_id) ? $blog_id : null);
		
		if(!empty($url)){
			$page_to_crawl['home'] = $url;
		}

		foreach($pages as $p){
			$page_to_crawl[$p->ID] = get_page_link($p->ID);
		}

		return $page_to_crawl;
	}
	
	// Adds the generated css and asynchronyses the css includes
	static function update_css($url, $css){
		global $speedycache;
		
		if(empty($url)){
			return false;
		}
		
		if(empty($css) && file_exists(speedycache_cache_path('critical-css/') . md5($url) . '.css')){
			$css = file_get_contents(speedycache_cache_path('critical-css/') . md5($url) . '.css');
		}
		
		if(empty($css)){
			return false;
		}

		$css = '<style id="speedycache-generated-criticalcss">'. "\n". wp_strip_all_tags($css) . '</style>';

		$url = parse_url($url);
		$uri = !empty($url['path']) ?  $url['path'] : '';
		$cache_loc = $uri . '/index.html';

		if(empty($cache_loc)){
			return;
		}
		
		if(!empty($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'SpeedyCacheTest'){
			$cache_path = speedycache_cache_path('test' . $cache_loc);
		} else {
			$cache_path = speedycache_cache_path('all' . $cache_loc);
		}

		$cache_path = rtrim($cache_path, '/');
		
		// For Desktop
		\SpeedyCache\CriticalCss::update_cached($cache_path, $css);

		if(!empty($speedycache->options['mobile_theme']) && $_SERVER['HTTP_USER_AGENT'] !== 'SpeedyCacheTest'){
			$cache_mobile = speedycache_cache_path('mobile-cache' . $cache_loc);
			
			// For Mobile Cache
			if(file_exists($cache_mobile)){
				\SpeedyCache\CriticalCss::update_cached($cache_mobile, $css);
			}	
		}

	}
	
	// Updates the content of the cached file
	static function update_content($content, $css){
		
		if(strpos($content, 'speedycache-generated-criticalcss') !== FALSE){
			$content = preg_replace('/<style id="speedycache-generated-criticalcss">(.*)<\/style>/sU', $css, $content);
		} else{
			$content = preg_replace('#</title>#iU', "</title>\n". $css, $content);
		}

		$content = \SpeedyCache\CriticalCss::make_css_defer($content);
		
		return $content;
	}
	
	/**
	 * This extracts the stylesheet links and convertes them to preload to make them async,
	 * and add the stylesheet links in noscript if js is disabled in some browsers
	 */
	static function make_css_defer($content){
		
		$css_links = '/(?=<link[^>]*\s(rel\s*=\s*[\'"]stylesheet["\']))<link[^>]*\shref\s*=\s*[\'"]([^\'"]+)[\'"](.*)>/iU';
		
		preg_match_all($css_links, $content, $matches, PREG_SET_ORDER, 0);

		if(empty($matches)){
			return $content;
		}
		
		$noscript_wrap = '<noscript>';

		foreach($matches as $tag){
			$preload = str_replace('stylesheet', 'preload', $tag[1]);
			$onload = preg_replace('~' . preg_quote($tag[3], '~') . '~iU', ' as="style" onload="" ' . $tag[3] . '>', $tag[3]);

			$new_tag = str_replace($tag[3] . '>', $onload, $tag[0]);
			$new_tag = str_replace($tag[1], $preload, $new_tag);
			$new_tag = str_replace('onload=""', 'onload="this.onload=null;this.rel=\'stylesheet\'"', $new_tag);
			$new_tag = preg_replace('/(id\s*=\s*[\"\'](?:[^\"\']*)*[\"\'])/i', '', $new_tag);

			$content = str_replace($tag[0], $new_tag, $content);
			
			$noscript_wrap .= $tag[0];
		}
		
		$noscript_wrap .= '</noscript>';
		
		$content = str_replace($noscript_wrap, '', $content);
		
		return str_replace('</body>', $noscript_wrap . '</body>', $content);

	}
	
	static function status_modal(){
		$html = '<!--SpeedyCache Critical CSS Logs Modal Starts Here-->
	<div modal-id="speedycache_critical_css" class="speedycache-modal">
		<div class="speedycache-modal-wrap">
			<div class="speedycache-modal-header">
				<div>'.esc_html__('Critical Cache Logs', 'speedycache').'</div>
				<div title="Close Modal" class="speedycache-close-modal">
					<span class="dashicons dashicons-no"></span>
				</div>
			</div>
			<div class="speedycache-modal-content" style="min-height:50vh;">
				<div class="speedycache-critical-css-status">';
			
			$generate_ccss = get_option('speedycache_ccss_logs', []);
			
			$scheduled = self::get_schedule(array('speedycache_generate_ccss'));
		
			if(!empty($scheduled)){
				$time = 'now';
				if(!empty($scheduled[0]['time']) && ($scheduled[0]['time'] - time()) > 0){
					$time = 'in ' . ($scheduled[0]['time'] - time()) . 's';
				}

				$html .= '<p style="color:rgb(1, 67, 97); background-color: rgb(229, 246, 253); padding: 10px; border-radius: 6px; font-family: monospace;">'. esc_html__('A process has been scheduled and will be executed', 'speedycache'). ' <strong>' . esc_html($time).'</strong></p>';
			}

			if(count($generate_ccss) < 1){
				$html .= '<span>'.esc_html__('No Logs found for CriticalCss', 'speedycache').'</span>';
			} else {
				$html .='<table style="margin:auto; width: 100%;">
					<thead>
						<tr>
							<th class="speedycache-table-hitem" scope="col">'.esc_html__('Time', 'speedycache').'</th>
							<th class="speedycache-table-hitem" scope="col">'. esc_html__('URLs', 'speedycache').'</th>
							<th class="speedycache-table-hitem" scope="col">'. esc_html__('Status', 'speedycache').'</th>
						</tr>
					</thead>
					<tbody>';
					
					$generate_ccss = array_reverse($generate_ccss);
					
					foreach($generate_ccss as $url => $status){
						$parsed_url = wp_parse_url($url);
						$path = !empty($parsed_url['path']) ? $parsed_url['path'] : '/';
						
						if($status['message'] == 'success'){
							$status_html = '<span class="dashicons dashicons-yes-alt" style="color:	#198754;" title="Success"></span>';
						} else {
							$status_html = '<div class="speedycache-tt"><span class="dashicons dashicons-info" style="color:#DC3545;"></span><span class="speedycache-tt-text">'.esc_html($status['message']).'</span></div>';
						}
						
						$html .= '<tr><td class="speedycache-table-item">'.esc_html($status['time']).'</td>
						<td class="speedycache-table-item">'.esc_html($path).'</td>
						<td class="speedycache-table-item" style="text-align:right;">'.wp_kses_post($status_html).'</td></tr>';
					}

				$html .= '</tbody>
				</table>';
			}
			
			$html .= '</div>
		</div>
	</div>
</div>';

		return $html;
	}

}
premium.php000064400000000606151526435070006745 0ustar00<?php

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT');
}

global $pagenow;
if(in_array($pagenow, ['post-new.php', 'post.php'], true)){
	add_action('admin_enqueue_scripts', '\SpeedyCache\MetaboxPro::enqueue_scripts');
	add_filter('speedycache_pro_metabox', '\SpeedyCache\MetaboxPro::html', 10, 2);
	add_filter('speedycache_metabox_fields', '\SpeedyCache\MetaboxPro::options');
}object-cache-lib.php000064400000025556151526435070010355 0ustar00<?php

if(!defined( 'WPINC' )){
	die();
}

/**
 * Object Cache API
 *
 * @link https://developer.wordpress.org/reference/classes/wp_object_cache/
 *
 * @package WordPress
 * @subpackage Cache
 */

/** WP_Object_Cache class */
require_once $plugin_dir . '/main/objectcache.php';


function wp_cache_init() {
	$GLOBALS['wp_object_cache'] = WP_Object_Cache::get_instance();
}

function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->add( $key, $data, $group, (int) $expire );
}

function wp_cache_add_multiple( array $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->add_multiple( $data, $group, $expire );
}

function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->replace( $key, $data, $group, (int) $expire );
}

function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->set( $key, $data, $group, (int) $expire );
}

function wp_cache_set_multiple( array $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->set_multiple( $data, $group, $expire );
}

function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
	global $wp_object_cache;

	return $wp_object_cache->get( $key, $group, $force, $found );
}

function wp_cache_get_multiple( $keys, $group = '', $force = false ) {
	global $wp_object_cache;

	return $wp_object_cache->get_multiple( $keys, $group, $force );
}

function wp_cache_delete( $key, $group = '' ) {
	global $wp_object_cache;

	return $wp_object_cache->delete( $key, $group );
}

function wp_cache_delete_multiple( array $keys, $group = '' ) {
	global $wp_object_cache;

	return $wp_object_cache->delete_multiple( $keys, $group );
}

function wp_cache_incr( $key, $offset = 1, $group = '' ) {
	global $wp_object_cache;

	return $wp_object_cache->incr( $key, $offset, $group );
}

function wp_cache_decr( $key, $offset = 1, $group = '' ) {
	global $wp_object_cache;

	return $wp_object_cache->decr( $key, $offset, $group );
}


function wp_cache_flush() {
	global $wp_object_cache;

	return $wp_object_cache->flush();
}

function wp_cache_flush_runtime() {
	return wp_cache_flush();
}

function wp_cache_flush_group( $group ) {
	global $wp_object_cache;

	return $wp_object_cache->flush_group( $group );
}

function wp_cache_supports( $feature ) {
	switch ( $feature ) {
		case 'add_multiple':
		case 'set_multiple':
		case 'get_multiple':
		case 'delete_multiple':
		case 'flush_runtime':
		case 'flush_group':
			return true;

		default:
			return false;
	}
}


function wp_cache_close() {
	return true;
}


function wp_cache_add_global_groups( $groups ) {
	global $wp_object_cache;

	$wp_object_cache->add_global_groups( $groups );
}


function wp_cache_add_non_persistent_groups( $groups ) {
	// Default cache doesn't persist so nothing to do here.
}

function wp_cache_switch_to_blog( $blog_id ) {
	global $wp_object_cache;

	$wp_object_cache->switch_to_blog( $blog_id );
}

function wp_cache_reset() {
	_deprecated_function( __FUNCTION__, '3.5.0', 'wp_cache_switch_to_blog()' );

	global $wp_object_cache;

	$wp_object_cache->reset();
}


#[AllowDynamicProperties]
class WP_Object_Cache {

	private $cache = array();
	public $cache_hits = 0;
	public $cache_misses = 0;
	protected $global_groups = array();
	private $blog_prefix;
	private $multisite;
	public $object_cache;
	static $instance;

	public function __construct() {
		$this->object_cache = \SpeedyCache\ObjectCache::get_instance();

		$this->multisite = is_multisite();
		$this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
	}
	
	static function get_instance(){
		if(self::$instance){
			return self::$instance;
		}
		
		self::$instance = new self;
		
		return self::$instance;
	}

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

	public function __set( $name, $value ) {
		return $this->$name = $value;
	}

	public function __isset( $name ) {
		return isset( $this->$name );
	}

	public function __unset( $name ) {
		unset( $this->$name );
	}

	protected function is_valid_key( $key ) {

		if ( is_int( $key ) ) {
			return true;
		}

		if ( is_string( $key ) && trim( $key ) !== '' ) {
			return true;
		}

		$type = gettype( $key );

		if ( ! function_exists( '__' ) ) {
			wp_load_translations_early();
		}

		$message = is_string( $key )
			? __( 'Cache key must not be an empty string.' )
			/* translators: %s: The type of the given cache key. */
			: sprintf( __( 'Cache key must be integer or non-empty string, %s given.' ), $type );

		_doing_it_wrong(
			sprintf( '%s::%s', __CLASS__, debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 )[1]['function'] ),
			$message,
			'6.1.0'
		);

		return false;
	}

	protected function _exists( $key, $group ) {
		if(!$id = $this->id($key, $group)){
			return false;
		}
		
		return isset($this->cache[$group][$id]);
	}

	public function add( $key, $data, $group = 'default', $expire = 0 ) {
		if(wp_suspend_cache_addition()){
			return false;
		}

		if(! $this->is_valid_key($key)){
			return false;
		}

		if($this->_exists($key, $group)){
			return false;
		}

		return $this->set($key, $data, $group, (int) $expire);
	}

	public function add_multiple( array $data, $group = '', $expire = 0 ) {
		$values = array();

		foreach ( $data as $key => $value ) {
			$values[ $key ] = $this->add( $key, $value, $group, $expire );
		}

		return $values;
	}

	public function replace( $key, $data, $group = 'default', $expire = 0 ) {
		if ( ! $this->is_valid_key( $key ) ) {
			return false;
		}
		
		if(!$id = $this->id($key, $group)){
			return false;
		}

		if (!$this->_exists($key, $group)){
			if(!$this->object_cache::exists($id)){
				return false;
			}
		}

		return $this->set( $key, $data, $group, (int) $expire );
	}

	public function set( $key, $data, $group = 'default', $expire = 0 ) {
		if(! $this->is_valid_key($key)){
			return false;
		}

		if(is_object($data)){
			$data = clone $data;
		}

		if(!$id = $this->id($key, $group)){
			return false;
		}

		if(!in_array($group, $this->object_cache::$non_cache_group)){
			$this->object_cache::set($id, $data, (int) $expire);
		}

		$this->cache[$group][$id] = $data;

		return true;
	}

	public function set_multiple( array $data, $group = '', $expire = 0 ) {
		$values = array();

		foreach ( $data as $key => $value ) {
			$values[ $key ] = $this->set( $key, $value, $group, $expire );
		}

		return $values;
	}

	public function get( $key, $group = 'default', $force = false, &$found = null ) {
		if ( ! $this->is_valid_key( $key ) ) {
			return false;
		}
		
		if(!$id = $this->id($key, $group)){
			$found = false;
			$this->cache_misses += 1;
			return false;
		}
		
		// In memory cache
		if($this->_exists($key, $group)){
			$found = true;
			$this->cache_hits += 1;
			return $this->cache[$group][$id];
		}

		// Non Cache Group check.
		if(empty($this->object_cache) || in_array($group, $this->object_cache::$non_cache_group)){
			$found = false;
			$this->cache_misses += 1;
			return false;
		}
		
		// Fetch cache from redis.
		if($cache = $this->object_cache::get($id)){
			$found = true;
			$this->cache_hits += 1;
			
			if(is_serialized($cache)){
				$cache = maybe_unserialize($cache);
			}

			$this->cache[$group][$id] = $cache;
			return $this->cache[$group][$id];
		}

		$found = false;
		$this->cache_misses += 1;
		return false;
	}

	public function get_multiple($keys, $group = 'default', $force = false) {
		$values = array();

		foreach($keys as $key){
			$values[$key] = $this->get($key, $group, $force);
		}

		return $values;
	}

	public function delete($key, $group = 'default', $deprecated = false) {
		if (! $this->is_valid_key($key)){
			return false;
		}

		if(!$id = $this->id($key, $group)){
			return false;
		}

		if(empty($this->cache[$group]) && empty($this->cache[$group][$id]) && !$this->object_cache::exists($id)) {
			return false;
		}

		unset($this->cache[$group][$id]);
		$this->object_cache::delete($id);
		return true;
	}

	public function delete_multiple(array $keys, $group = ''){
		$values = array();

		foreach($keys as $key){
			$values[$key] = $this->delete($key, $group);
		}

		return $values;
	}

	public function incr($key, $offset = 1, $group = 'default'){
		return $this->incr_desr($key, $offset = 1, $group, true);
	}

	public function decr($key, $offset = 1, $group = 'default'){
		return $this->incr_desr($key, $offset = 1, $group, false);
	}
	
	public function incr_desr($key, $offset = 1, $group = 'default', $incr = true){
		if (! $this->is_valid_key($key)){
			return false;
		}

		$cache_val = $this->get($key, $group);

		if(false === $cache_val){
			return false;
		}

		if(! is_numeric( $cache_val)){
			$cache_val = 0;
		}

		$offset = (int) $offset;

		if($incr){
			$cache_val += $offset;
		}
		else {
			$cache_val -= $offset;
		}

		if ( $cache_val < 0 ) {
			$cache_val = 0;
		}

		$this->set($key, $cache_val, $group);

		return $cache_val;
	}

	public function flush() {
		$this->cache = array();

		if(!empty($this->object_cache)){
			$this->object_cache::flush_db();
		}

		return true;
	}

	public function flush_group($group) {
		unset($this->cache[$group]);

		return true;
	}

	public function add_global_groups($groups){
		$groups = (array) $groups;

		$groups = array_fill_keys($groups, true);
		$this->global_groups = array_merge($this->global_groups, $groups);
	}
	
	public function is_global($group){
		return in_array($group, $this->global_groups);
	}

	public function switch_to_blog($blog_id){
		$blog_id = (int) $blog_id;
		$this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
	}

	public function reset(){
		_deprecated_function(__FUNCTION__, '3.5.0', 'WP_Object_Cache::switch_to_blog()');

		// Clear out non-global caches since the blog ID has changed.
		foreach(array_keys($this->cache) as $group){
			if(! isset( $this->global_groups[$group])){
				unset($this->cache[$group]);
			}
		}
	}

	public function stats() {
		echo '<p>';
		echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
		echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
		echo '</p>';
		echo '<ul>';
		foreach($this->cache as $group => $cache){
			echo '<li><strong>Group:</strong> ' . esc_html($group) . ' - ( ' . number_format(strlen(serialize($cache)) / KB_IN_BYTES, 2 ) . 'k )</li>';
		}
		echo '</ul>';
	}
	
	public function id($key, $group){
		$prefix = $this->is_global($group) ? '' : $this->blog_prefix;
		
		if(empty($group)){
			$group = 'default';
		}

		return  $prefix . $group . '.' . $key;
	}
}logs.php000064400000016656151526435070006247 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class Logs{

	static function log($type){
		global $speedycache;
		
		$speedycache->logs = array();
		$speedycache->logs['type'] = $type;
		$speedycache->logs['name'] = '';
		$speedycache->logs['limit'] = 0;
		$speedycache->logs['logs'] = array();
		
		if($speedycache->logs['type'] == 'delete'){
			$speedycache->logs['name'] = 'speedycache_delete_cache_logs';
			$speedycache->logs['limit'] = 25;
		}
		
		self::set_logs();
	}

	static function update_db(){
		global $speedycache;
		
		if(get_option($speedycache->logs['name'])){
			update_option($speedycache->logs['name'], $speedycache->logs['logs'], false);
		}else{
			update_option($speedycache->logs['name'], $speedycache->logs['logs'], false);
		}
	}

	static function set_logs(){
		global $speedycache;

		if($log = get_option($speedycache->logs['name'])){
			$speedycache->logs['logs'] = $log;
		}
	}

	// To detect which static function called delete_cache()
	static function decode_via($data){

		$return_res = '';
		
		switch($data['function']){
			case 'all_cache':
				$return_res = '- All cache files deleted from Manage Cache';
				break;

			case 'delete_single':
				$return_res = '- Cache of a page got deleted';
				break;
				
			case 'gravatar':
				$return_res = '- Gravatar cache deleted';
				break;
				
			case 'minified':
				$return_res = '- Minified and combined assets deleted';
				break;

			case 'cache':
			
				if(empty($data['args'][0])){
					$return_res = '- Cache of a page got deleted';
					break;
				}
			
				$return_res = '- Cache of a page #ID:'.$data['args'][0].' got deleted';
				break;
				
			case 'purge_varnish':
				$return_res = '- Varnish Cache got Purged Successfully';
				break;
			
			case 'on_status_transitions':
			case 'on_status_change':
				if(empty($data['args'])){
					$return_res = '- Cache of one page has been purged on page status transition';
					break;
				}

				$type = $data['args'][2]->post_type;
			
				if($data['args'][0] == 'publish' && $data['args'][1] == 'publish'){
					$return_res = '- The '.$type.' has been updated- #ID:'.$data['args'][2]->ID.' - One cached file has been removed';
				}else if($data['args'][0] == 'publish' && $data['args'][1] != 'publish'){
					$return_res = '- New '.$type.' has been published - '.$type.' ID:'.$data['args'][2]->ID;
				}else {
					$return_res = '- The '.$type.' status has been changed. - '.$data['args'][1].' > '.$data['args'][0].' #ID:'.$data['args'][2]->ID;
				}
				
				break;
			
			case 'wp_set_comment_status':
			case 'on_comment_status':
				if(empty($data['args'])){
					$return_res = '- Post cache deleted becuase of comment status change';
					break;
				}
			
					
				if(isset($data['args'][2]->comment_ID)){
					$return_res = '- Comment(ID: '.$data['args'][2]->comment_ID.') has been marked as '.$data['args'][1].' - One cached file has been removed';
				}else{
					$return_res = '- Comment has been marked as '.$data['args'][1].' - Comment ID: '.$data['args'][0].' - One cached file has been removed';
				}
				
				break;
		}
		
		if(!empty($return_res)){
			return $return_res;
		}

		return $data['function'];
	}

	static function get_via(){
		$arr = array();
		$via = debug_backtrace();
		
		// TODO: Need to remove unwanted code from this
		if(isset($via[8]) && ($via[8]['function'] == 'wp_set_comment_status') && ($via[2]['function'] == 'home_page_cache') && ($via[3]['function'] == 'speedycache_single_delete_cache')){
			return false;
		}
		
		if($via[3]['function'] == 'speedycache_delete_home_page_cache'){
			return false;
		}

		if($via[4]['function'] == 'clear_cache_after_woocommerce_checkout_order_processed'){
			$arr['args'] = array();
			$arr['function'] = $via[4]['function'];

			$order = wc_get_order($via[4]['args'][0]);

			if($order){
				foreach($order->get_items() as $item_key => $item_values ){
					array_push($arr['args'], $item_values->get_product_id());
				}
			}
		}elseif($via[4]['function'] === 'speedycache_set_schedule'){
			$arr['function'] = $via[4]['function'];
			$arr['args'] = $via[4]['args'];
		}elseif($via[2]['function'] == 'varnish'){
			$arr['function'] = $via[2]['function'];
		}else if($via[3]['function'] == 'on_status_transitions' || $via[3]['function'] == 'speedycache_single_delete_cache'){
			$arr['args'] = $via[3]['args'];
			$arr['function'] = $via[3]['function'];
		}
		else if($via[3]['function'] == 'on_comment_status' || $via[3]['function'] == 'on_status_change'){
			$arr['args'] = $via[3]['args'];
			$arr['function'] = $via[3]['function'];
		}else if($via[4]['function'] == 'speedycache_delete_css_and_js_cache_toolbar' || $via[4]['function'] == 'speedycache_delete_cache_toolbar'){
			$arr['function'] = $via[4]['function'];
		}else if(isset($via[7]) && ($via[7]['function'] == 'wp_set_comment_status')){
			$arr['args'] = $via[7]['args'];
			$arr['function'] = $via[7]['function'];
		}else if(isset($via[6]) && ($via[3]['function'] == 'apply_filters' && $via[6]['function'] == 'speedycache_clear_all_cache')){
			$arr['file'] = $via[6]['file'];
			$arr['function'] = $via[6]['function'];
		}else if(in_array($via[2]['function'], ['all_cache', 'gravatar', 'minified', 'purge_varnish'])){
			$arr['function'] = $via[2]['function'];
		}else if($via[2]['function'] == 'cache'){
			$arr['function'] = $via[2]['function'];
			$arr['args'] = $via[2]['args'];
		}else{
			$arr['function'] = $via[3]['function'];

			if(isset($via[3]['file']) && $via[3]['file']){
				if(preg_match("/\/plugins\/([^\/]+)\//", $via[3]['file'], $plugin_name)){
					$arr['function'] = $arr['function'].' ('.$plugin_name[1].')';
				}
			}
		}

		return $arr;
	}

	static function action($from = ''){
		global $speedycache;
		
		if($speedycache->logs['type'] == 'delete'){
			$log = [];
			$log['date'] = date('d-m-Y @ H:i:s', current_time('timestamp'));
			
			if($from && $from['prefix'] != 'all'){
				$log['via'] = [];
				$log['via']['function'] = '- Cache Timeout / '.$from['prefix'].' '.$from['content'];
			}else{
				$log['via'] = self::get_via();
			}
		}
		
		if($log && $log['via'] !== false){
			
			if(!in_array($log, $speedycache->logs['logs'])){
				array_unshift($speedycache->logs['logs'], $log);

				if($speedycache->logs['limit'] < count($speedycache->logs['logs'])){
					array_pop($speedycache->logs['logs']);
				}

				self::update_db();
			}
		}
	}

	static function print_logs(){
		global $speedycache;

		?>
		<div id="speedycache-delete-logs">
			<div class="speedycache-block">
				<div class="speedycache-block-title">
					<h2>Delete Cache Logs</h2>
				</div>

				<table class="speedycache-log-table">
					<thead>
						<tr>
							<th scope="col">Date</th>
							<th scope="col">Via</th>
						</tr>
					</thead>
					<tbody>
						<?php if($speedycache->logs['logs'] && count($speedycache->logs['logs']) > 0){ ?>
							<?php foreach($speedycache->logs['logs'] as $key => $log){ ?>
								<tr>
									<td scope="row"><?php echo isset($log['date']) ? esc_html($log['date']) : '';?></td>
									<td style="border-right:1px solid #DEDBD1;"><?php echo isset($log['via']) ? esc_html(self::decode_via($log['via'])) : ''; ?></td>
								</tr>
							<?php } ?>
						<?php }else{ ?>
								<tr>
									<td style="border-left:1px solid #DEDBD1;" scope="row"><label>No Log</label></td>
									<td style="border-right:1px solid #DEDBD1;"></td>
								</tr>
						<?php } ?>
					</tbody>
				</table>
			</div>
		</div>
		<?php
	}

}

settingspage.php000064400000103156151526435100007762 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class SettingsPage{
	
	static function license_tab(){
		global $speedycache;
		
		echo '<div class="speedycache-tab" id="speedycache-license">
			<h2><img src="'.SPEEDYCACHE_URL.'/assets/images/icons/license.svg" height="32" width="32"/> License</h2>
			<table class="wp-list-table fixed striped users speedycache-license-table" cellspacing="1" border="0" width="78%" cellpadding="10" align="center">
				<tbody>
					<tr>				
						<th align="left" width="25%">'.esc_html__('SpeedyCache Version', 'speedycache').'</th>
						<td>'.SPEEDYCACHE_PRO_VERSION.(defined('SPEEDYCACHE_PRO') ? ' (Pro Version)' : '').'</td>
					</tr>
					<tr>			
						<th align="left" valign="top">'.esc_html__('SpeedyCache License', 'speedycache').'</th>
						<td align="left">
							<form method="post" action="">
								<span style="color:var(--speedycache-red)">
									'.(defined('SPEEDYCACHE_PRO') && empty($speedycache->license) ? '<span style="color:var(--speedycache-red)">Unlicensed</span> &nbsp; &nbsp;' : '').'
								</span>
								<input type="hidden" name="security" value="'.wp_create_nonce('speedycache_license').'"/>
								<input type="hidden" name="action" value="speedycache_verify_license"/>
								<input type="text" name="license" value="'.(empty($speedycache->license) ? empty($_POST['license']) ? '' : \SpeedyCache\Util::sanitize_post('speedycache_license') : $speedycache->license['license']).'" size="30" placeholder="e.g. SPDFY-11111-22222-33333-44444" style="width:300px;">
								<button class="speedycache-button speedycache-btn-black" id="speedycache-license-btn" type="submit">Update License<span class="speedycache-spinner"><span></button>
							</form>';
							if(!empty($speedycache->license)){
								$expires = $speedycache->license['expires'];
								$expires = substr($expires, 0, 4).'/'.substr($expires, 4, 2).'/'.substr($expires, 6);
								
								echo '<div style="margin-top:10px;">License Status : '.(empty($speedycache->license['status_txt']) ? 'N.A.' : wp_kses_post($speedycache->license['status_txt'])).' &nbsp; &nbsp; &nbsp;';
								
								if(empty($speedycache->license['has_plid']) || $speedycache->license['expires'] <= date('Ymd')){
									echo 'License Expires : '.($speedycache->license['expires'] <= date('Ymd') ? '<span style="color:var(--speedycache-red)">'.esc_attr($expires).'</span>' : esc_attr($expires));
								}
								echo '</div>';
							}
						echo '</td>
					</tr>
					<tr>
						<th align="left">URL</th>
						<td>'.get_site_url().'</td>
					</tr>
					<tr>				
						<th align="left">Path</th>
						<td>'.ABSPATH.'</td>
					</tr>
					<tr>				
						<th align="left">Server\'s IP Address</th>
						<td>'.esc_html($_SERVER['SERVER_ADDR']).'</td>
					</tr>
					<tr>				
						<th align="left">.htaccess is writable</th>
						<td>'.(is_writable(ABSPATH.'/.htaccess') ? '<span style="color:var(--speedycache-red)">Yes</span>' : '<span style="color:green">No</span>').'</td>
					</tr>		
				</tbody>
			</table>
		</div>';
	}
	
	// Earlier we use to just log deletion, but now we will log other stuff too.
	static function logs(){
		global $speedycache;
		
		$speedycache->logs['logs'] = get_option('speedycache_delete_cache_logs', []);

		echo '<div class="speedycache-logs">
			<div class="speedycache-logs-header">SpeedyCache Logs</div>
			<div class="speedycache-logs-content">';
			if(!empty($speedycache->logs['logs']) && count($speedycache->logs['logs']) > 0){
				foreach($speedycache->logs['logs'] as $key => $log){
					echo '<div class="speedycache-logs-row">'.(isset($log['date']) ? esc_html($log['date']) : '') . (isset($log['via']) ? esc_html(\SpeedyCache\Logs::decode_via($log['via'])) : '').'</div>';
				}
			}else{
				echo '<div class="speedycache-logs-row">'. esc_html__('No logs found', 'speedycache'). '</div>';
			}

			echo '</div>
		</div>';
	}
	
	static function stats(){
		global $speedycache;
		
		if(!class_exists('\SpeedyCache\Util')){
			return;
		}

		// CACHE SIZE
		$cache_stats = get_option('speedycache_html_size', 0);

		if(empty($cache_stats)){
			$desktop_cache = \SpeedyCache\Util::cache_path('all');
			$cache_stats = 0;

			if(file_exists($desktop_cache)){
				$cache_stats = \SpeedyCache\Util::dir_size($desktop_cache);
			}
			
			$mobile_cache = \SpeedyCache\Util::cache_path('mobile-cache');

			if(file_exists($mobile_cache)){
				$cache_stats += \SpeedyCache\Util::dir_size($mobile_cache);
			}
			
			update_option('speedycache_html_size', $cache_stats);
		}
		
		// MINIFIED SIZE
		$assets_stats = get_option('speedycache_assets_size', 0);

		if(empty($assets_stats)){
			$assets_dir = \SpeedyCache\Util::cache_path('assets');
			$assets_stats = 0;

			if(file_exists($assets_dir)){
				$assets_stats = \SpeedyCache\Util::dir_size($assets_dir);
			}
			
			update_option('speedycache_assets_size', $assets_stats);
		}
		
		$img_count = 0;
		if(class_exists('\SpeedyCache\Image')){
			$img_count = \SpeedyCache\Image::optimized_file_count();
		}

		echo '<div class="speedycache-admin-row">
			<div class="speedycache-stats-block speedycache-is-block">
				<div class="speedycache-stats-name">Cache Stats</div>
				<div class="speedycache-stats-number">'.esc_html(size_format($cache_stats)).'</div>
				<div class="speedycache-stat-status"><span class="speedycache-stat-status-indicator" '.(!empty($speedycache->options['status'])? 'style="background-color:#0c6;"' : '').'></span><span>Enabled</span></div>
			</div>
			<div class="speedycache-stats-block speedycache-is-block">
				<div class="speedycache-stats-name">Assets Stats</div>
				<div class="speedycache-stats-number">'.esc_html(size_format($assets_stats)).'</div>
			</div>
			<div class="speedycache-stats-block speedycache-is-block">
				<div class="speedycache-stats-name">Object Cache Stats</div>
				<div class="speedycache-stats-number">'.esc_html($speedycache->object_memory).'</div>
				<div class="speedycache-stat-status"><span class="speedycache-stat-status-indicator" '.(!empty($speedycache->object['enable'])? 'style="background-color:#0c6;"' : '').'></span><span>Enabled</span></div>
			</div>
			<div class="speedycache-stats-block speedycache-is-block">
				<div class="speedycache-stats-name">Image Stats</div>
				<div class="speedycache-stats-number">'.esc_html($img_count).' IMG</div>
			</div>
		</div>';
	}
	
	static function image_optm(){
		echo '<h2><img src="'.SPEEDYCACHE_URL.'/assets/images/icons/image.svg" height="32" width="32"/> Image Optimization</h2>';
		
		\SpeedyCache\Image::statics();
		\SpeedyCache\Image::settings();
		\SpeedyCache\Image::list_image_html();
	}
	
	static function bloat_tab(){
		global $speedycache;
		
		echo '<h2><img src="'.SPEEDYCACHE_URL.'/assets/images/icons/broom.svg" height="32" width="32"/> Bloat Remover</h2>
		<form method="post">
		<input type="hidden" name="action" value="speedycache_save_bloat_settings"/>';
		wp_nonce_field('speedycache_ajax_nonce');

		if(!defined('SPEEDYCACHE_PRO')){
			return;
		}
		
		$bloat_options = array(
			'disable_xmlrpc' => array(
				'id' => 'speedycache_disable_xmlrpc',
				'title' => __('Disable XML RPC', 'speedycache'),
				'description' => __('XML-RPC can cause performance and security issues'),
			),
			'remove_gfonts' => array(
				'id' => 'speedycache_remove_gfonts',
				'title' => __('Disable Google Fonts', 'speedycache'),
				'description' => __('Use users system fonts to prevent loading of fonts from server', 'speedycache'),
			),
			'disable_jmigrate' => array(
				'id' => 'speedycache_disable_jmigrate',
				'title' => __('Disable jQuery Migrate', 'speedycache'),
				'description' => __('Disable jQuery Migrate for better speed.', 'speedycache'),
				'docs' => 'https://speedycache.com/docs/bloat-remover/how-to-remove-jquery-migrate-in-wordpress/',
			),
			'disable_dashicons' => array(
				'id' => 'speedycache_disable_dashicons',
				'title' => __('Disable DashIcons', 'speedycache'),
				'description' => __('DashIcons are used on WordPress admin and might not be used on Front End.', 'speedycache'),
			),
			'disable_gutenberg' => array(
				'id' => 'speedycache_disable_gutenberg',
				'title' => __('Disable Gutenberg', 'speedycache'),
				'description' => __('Decouple Gutenberg if you use another page builder.', 'speedycache'),
			),
			'disable_block_css' => array(
				'id' => 'speedycache_disable_block_css',
				'title' => __('Disable Block Editor CSS', 'speedycache'),
				'description' => __('Some themes might not use Block Editor CSS on the front.', 'speedycache'),
			),
			'disable_oembeds' => array(
				'id' => 'speedycache_disable_oembeds',
				'title' => __('Disable OEmbeds', 'speedycache'),
				'description' => __('OEmbeds increases load on site if a lot of embeds are being used.', 'speedycache'),
			),
			'update_heartbeat' => array(
				'id' => 'speedycache_update_heartbeat',
				'title' => __('Update Heartbeat', 'speedycache'),
				'description' => __('Change how frequently heartbeat is checked.', 'speedycache'),
				'settings' => 'speedycache_update_heartbeat',
			),
			'limit_post_revision' => array(
				'id' => 'speedycache_limit_post_revision',
				'title' => __('Limit Post Revision', 'speedycache'),
				'description' => __('Change how many post revision you want to keep.', 'speedycache'),
				'settings' => 'speedycache_limit_post_revision',
			),
			'disable_cart_fragment' => array(
				'id' => 'speedycache_disable_cart_fragment',
				'title' => __('Disable Cart Fragments', 'speedycache'),
				'description' => __('Disable WooCommerce cart fragments for better performance.', 'speedycache'),
			),
			'disable_woo_assets' => array(
				'id' => 'speedycache_disable_woo_assets',
				'title' => __('Disable WooCommerce Assets', 'speedycache'),
				'description' => __('Disables WooCommerce assets to reduce unwanted asset loading.', 'speedycache'),
				'docs' => 'https://speedycache.com/docs/bloat-remover/how-to-remove-woocommerce-assets/',
			),
			'disable_rss' => array(
				'id' => 'speedycache_disable_rss',
				'title' => __('Disable RSS feeds', 'speedycache'),
				'description' => __('Disable RSS feeds to reduce request which use server resources.', 'speedycache'),
			),
		);
		
		foreach($bloat_options as $bloat_key => $bloat_option){
			echo '<div class="speedycache-option-wrap">
			<label for="'.esc_attr($bloat_option['id']).'" class="speedycache-custom-checkbox">
				<input type="checkbox" id="'.esc_attr($bloat_option['id']).'" name="'.esc_attr($bloat_key).'" '. (!empty($speedycache->bloat[$bloat_key]) ? ' checked' : '').'/>
				<div class="speedycache-input-slider"></div>
			</label>
			<div class="speedycache-option-info">
				<span class="speedycache-option-name"><span>'.esc_html($bloat_option['title']). '</span>';
				
				// Docs Link here
				if(isset($bloat_option['docs'])){
					echo '<a href="'.esc_url($bloat_option['docs']).'" target="_blank"><span class="dashicons dashicons-info" style="font-size:14px"></span></a>';
				}
				
				// Setting if any
				if(isset($bloat_option['settings'])){
				echo '<span class="speedycache-modal-settings-link" setting-id="'.esc_attr($bloat_option['settings']).'" style="display:'. (!empty($speedycache->bloat[$bloat_key]) ? 'inline-block' : 'none').';">- '.esc_html__('Settings', 'speedycache').'</span>';
				}
				echo '</span>
				<span class="speedycache-option-desc">'. esc_html($bloat_option['description']).'</span> 
			</div>
		</div>';
		}
		
		// Bloat modals
		echo '<div modal-id="speedycache_limit_post_revision" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Limit Post Revision', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content">
					<label for="speedycache_post_revision_count">'.esc_html__('Select Post Revision Count', 'speedycache').'</label>
					<select id="speedycache_post_revision_count" name="post_revision_count" value="'.(!empty($speedycache->bloat['post_revision_count']) ? esc_attr($speedycache->bloat['post_revision_count']) : '').'">';
						$post_revision_opts = array(
							'disable' => esc_html__('Disable', 'speedycache'),
							'1' => '1',
							'2' => '2',
							'3' => '3',
							'4' => '4',
							'5' => '5',
							'10' => '10',
							'20' => '20',
						);
						
						foreach($post_revision_opts as $value => $post_revision_opt){
							$selected = '';
							
							if(!empty($speedycache->bloat['post_revision_count']) && $speedycache->bloat['post_revision_count'] == $value){
								$selected = 'selected';
							} elseif(empty($speedycache->bloat['post_revision_count']) && $value == '10'){
								$selected = 'selected';
							}

							echo '<option value="'.esc_attr($value).'" '.esc_attr($selected).'>'.esc_html($post_revision_opt).'</option>';
						}
					echo '</select>
	
				</div>
				<div class="speedycache-modal-footer">
					<button type="button" action="close">
						<span>'.esc_html__('Submit', 'speedycache').'</span>
					</button>
				</div>
			</div>
		</div>
		
		<!-- Modal Settings for heartbeat of WordPress -->
		<div modal-id="speedycache_update_heartbeat" class="speedycache-modal">
			<div class="speedycache-modal-wrap">
				<div class="speedycache-modal-header">
					<div>'.esc_html__('Update HeartBeat', 'speedycache').'</div>
					<div title="Close Modal" class="speedycache-close-modal">
						<span class="dashicons dashicons-no"></span>
					</div>
				</div>
				<div class="speedycache-modal-content">';
					$heartbeat_modes = array(
						'15' => esc_html__('15 Seconds(Default)', 'speedycache'),
						'30' => esc_html__('30 seconds', 'speedycache'),
						'45' => esc_html__('45 Seconds', 'speedycache'),
						'60' => esc_html__('60 seconds', 'speedycache'),
						'120' => esc_html__('2 Minutes', 'speedycache'),
					);
					
					$disable_heartbeat = array(
						'dont' => esc_html__('Do not Disable', 'speedycache'),
						'disable' => esc_html__('Disable', 'speedycache'),
						'editor' => esc_html__('Allow on Editor only', 'speedycache'),
					);

					echo '<table>
					
					<tr>
					<td style="text-align:left;">
					<label for="speedycache_heartbeat_backend">'.esc_html__('Heartbeat Frequency', 'speedycache').'</label></td>
					<td><select id="speedycache_heartbeat_frequency" name="heartbeat_frequency" value="'.(!empty($speedycache->bloat['heartbeat_frequency']) ? esc_attr($speedycache->bloat['heartbeat_frequency']) : '').'">';
						foreach($heartbeat_modes as $value => $heartbeat_mode){
							$selected = '';
							
							if(!empty($speedycache->bloat['heartbeat_frequency']) && $speedycache->bloat['heartbeat_frequency'] == $value){
								$selected = 'selected';
							} elseif(empty($speedycache->bloat['heartbeat_frequency']) && $value == '120'){
								$selected = 'selected';
							}

							echo '<option value="'.esc_attr($value).'" '.esc_attr($selected).'>'.esc_html($heartbeat_mode).'</option>';
						}
					echo '</select></td></tr>';

					echo '<tr><td style="text-align:left;"><label for="speedycache_disable_heartbeat">'.esc_html__('Disable Heartbeat', 'speedycache').'</label></td>
					<td><select id="speedycache_disable_heartbeat" name="disable_heartbeat" value="'.(!empty($speedycache->bloat['disable_heartbeat']) ? esc_attr($speedycache->bloat['disable_heartbeat']) : '').'">';
						foreach($disable_heartbeat as $value => $disable_mode){
							$selected = '';
							
							if(!empty($speedycache->bloat['disable_heartbeat']) && $speedycache->bloat['disable_heartbeat'] == $value){
								$selected = 'selected';
							} elseif(empty($speedycache->bloat['disable_heartbeat']) && $value == 'dont'){
								$selected = 'selected';
							}

							echo '<option value="'.esc_attr($value).'" '.esc_attr($selected).'>'.esc_html($disable_mode).'</option>';
						}
					echo '</select></td></tr></table>';

				echo '</div>
				<div class="speedycache-modal-footer">
					<button type="button" action="close">
						<span>'.esc_html__('Submit', 'speedycache').'</span>
					</button>
				</div>
			</div>
		</div>';
		\SpeedyCache\Settings::save_btn();
		echo '</form>';
	}
	
	static function db_tab(){
		global $wpdb;
		
		echo '<h2><img src="'.SPEEDYCACHE_URL.'/assets/images/icons/db.svg" height="32" width="32"/> Database Optimizer</h2>';
		
		// TODO: Show notice which mentions about the bloat settings as we will slowly migrate the html code of bloat to the Pro version, to prevent the GPL plugin providers from making users fool.
		if(!defined('SPEEDYCACHE_PRO')){
			return;
		}
		
		$statics = array('all_warnings' => 0, 'post_revisions' => 0, 'trashed_contents' => 0, 'trashed_spam_comments' => 0, 'trackback_pingback' => 0, 'transient_options' => 0, 'expired_transient' => 0);
	
		$statics['post_revisions'] = $wpdb->get_var("SELECT COUNT(*) FROM `$wpdb->posts` WHERE post_type = 'revision';");

		$statics['trashed_contents'] = $wpdb->get_var("SELECT COUNT(*) FROM `$wpdb->posts` WHERE post_status = 'trash';");

		$statics['trashed_spam_comments'] = $wpdb->get_var("SELECT COUNT(*) FROM `$wpdb->comments` WHERE comment_approved = 'spam' OR comment_approved = 'trash' ;");

		$statics['trackback_pingback'] = $wpdb->get_var("SELECT COUNT(*) FROM `$wpdb->comments` WHERE comment_type = 'trackback' OR comment_type = 'pingback' ;");

		$element = "SELECT COUNT(*) FROM `$wpdb->options` WHERE option_name LIKE '%\_transient\_%' ;";
		$statics['transient_options'] = $wpdb->get_var( $element ) > 20 ? $wpdb->get_var( $element ) : 0;	

		$statics['expired_transient'] = $wpdb->get_var( "SELECT COUNT(*) FROM `$wpdb->options` WHERE option_name LIKE '_transient_timeout%' AND option_value < " . time() );

		$statics['all_warnings'] = $statics['all_warnings'] + $statics['transient_options'] + $statics['trackback_pingback']+ $statics['trashed_spam_comments']+ $statics['trashed_contents']+ $statics['post_revisions'];
		
		
		
		echo '<div speedycache-db-name="all_warnings" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Clean everything', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['all_warnings']).')</span></div>
					<div>'.esc_html__('Run the all options', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>

		<div speedycache-db-name="post_revisions" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Post Revisions', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['post_revisions']).')</span></div>
					<div>'.esc_html__('Clean the all post revisions', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>

		<div speedycache-db-name="trashed_contents" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Trashed Contents', 'speedycache').'<span class="speedycache-db-number">('.esc_html($statics['trashed_contents']).')</span></div>
					<div>'.esc_html__('Clean the all trashed posts & pages', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>

		<div speedycache-db-name="trashed_spam_comments" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Trashed & Spam Comments', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['trashed_spam_comments']).')</span></div>
					<div>'.esc_html__('Clean the all comments from trash & spam', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>

		<div speedycache-db-name="trackback_pingback" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Trackbacks and Pingbacks', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['trackback_pingback']).')</span></div>
					<div>'.esc_html__('Clean the all trackbacks and pingbacks', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>

		<div speedycache-db-name="transient_options" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Transient Options', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['transient_options']).')</span></div>
					<div>'.esc_html__('Clean the all transient options', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>
		<div speedycache-db-name="expired_transient" class="speedycache-db-row">
			<div>
				<div class="speedycache-db-info db">
					<div>'.esc_html__('Expired Transients', 'speedycache').' <span class="speedycache-db-number">('.esc_html($statics['expired_transient']).')</span></div>
					<div>'.esc_html__('Clean the expired transients', 'speedycache').'</div>
				</div>
			</div>
			<button class="speedycache-button speedycache-btn-black speedycache-db-optm-btn">'.esc_html__('Run optimization', 'speedycache').'<span class="speedycache-spinner"></span></button>
		</div>';
	}
	
	static function object_tab(){
		global $speedycache;
	
		echo '<h2><img src="'.SPEEDYCACHE_URL.'/assets/images/icons/object.svg" height="32" width="32"/> '.esc_html__('Object Cache', 'speedycache').'</h2>';

		echo '<div class="speedycache-block">
			<div class="speedycache-admin-row">
				<div class="speedycache-is-block speedycache-object-stat">
					<div style="display:flex; justify-content:space-between;">
						<div><strong>Caching Status:</strong>  '.(!empty($speedycache->object['enable']) ? '<span style="color:green;">Enabled</span>' : '<span style="color:red;">Disabled</span>').'</div>
						<div><strong>Memory Usage:</strong> <span>'.esc_html__($speedycache->object_memory).'</span></div>
					</div>
					<div class="speedycache-drop-in"><strong>Drop In:</strong> '.(defined('SPEEDYCACHE_OBJECT_CACHE') ? '<span style="color:green;">Valid</span>' : '<span style="color:red;">Not Valid</span>').'</div>
					<div><strong>phpRedis Status:</strong> '.(empty(phpversion('redis')) ? '<span style="color:red">' . esc_html__('phpRedis Not Found', 'speedycache') : (version_compare(phpversion('redis'), '3.1.1') > 0 ? '<span style="color:green">'. esc_html__('Available', 'speedycache') . '('.esc_html(phpversion('redis')).')' : '<span style="color:red">' . esc_html__('You are using older version of PHPRedis'))).'</span></div>';
					if(!empty($speedycache->object['hashed_prefix'])){
						echo'<div><strong>Hashed Prefix:</strong> <span>'.esc_html($speedycache->object['hashed_prefix']).'</span></div>';
					}
					echo'<button class="speedycache-button speedycache-btn-black speedycache-flush-db">Flush DB<span class="speedycache-spinner"></span></button>
				</div>
			</div>
			<div class="speedycache-object-charts"></div>
		</div>
		
		<div class="speedycache-block">
			<form method="POST">';
			wp_nonce_field('speedycache_ajax_nonce');
			echo '<input type="hidden" value="speedycache_save_object_settings" name="action">

			<div class="speedycache-block-title">
				<h2>'.esc_html__('Settings', 'speedycache').'</h2>
			</div>
			<table class="wp-list-table speedycache-table" style="width:100%;">
				<tr>
					<th><label for="speedycache_enable_object">'.esc_html__('Enable', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_enable_object" class="speedycache-custom-checkbox">
							<input type="checkbox" id="speedycache_enable_object" name="enable_object" '.((isset($speedycache->object['enable']) && $speedycache->object['enable']) ? ' checked="true"' : '').'/>
							<div class="speedycache-input-slider"></div>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Enables Object caching, if you have full page caching then it might show some conflicts.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr style="display:none;">
					<th><label for="speedycache_object_driver">'.esc_html__('Driver', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_driver">
							<select name="driver" id="speedycache_object_driver">
								<option value="Redis" selected>Redis</option>
							</select>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Choose which Object Cache Driver you want to use.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_host">'.esc_html__('Host', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_host">
							<input type="text" name="host" id="speedycache_object_host" value="'.(!empty($speedycache->object['host']) ? esc_attr($speedycache->object['host']) : 'localhost').'"/>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Your Redis host name or IP address.', 'speedycache').'</div>
					</td>
				</tr>

				<tr>
					<th><label for="speedycache_object_port">'.esc_html__('Port', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_port">
							<input type="text" name="port" id="speedycache_object_port" value="'.(!empty($speedycache->object['port']) ? esc_attr($speedycache->object['port']) : '6379').'"/>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Your Redis host port number', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_username">'.esc_html__('Username', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_username">
							<input type="password" id="speedycache_object_username" name="username" value="'. ((!empty($speedycache->object['username'])) ? esc_html($speedycache->object['username']) : '').'" />
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Username of your Redis acccount.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_password">'.esc_html__('Password', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_password">
							<input type="password" id="speedycache_object_password" name="password" value="'.((!empty($speedycache->object['password'])) ? esc_html($speedycache->object['password']) : '').'" />
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Password for your Redis Account.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_ttl">'.esc_html__('Object Time to live', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_ttl">
							<input type="text" name="ttl" id="speedycache_object_ttl" value="'.(!empty($speedycache->object['ttl']) ? esc_attr($speedycache->object['ttl']) : '360').'"/>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('How long you want the cached Object to persist', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_db_id">'.esc_html__('Redis DB ID', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_db_id">
							<input type="text" name="db-id" id="speedycache_object_db_id" value="'. (!empty($speedycache->object['db-id']) ? esc_attr($speedycache->object['db-id']) : '0').'" style="width:45px;"/>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Set the database number, make sure to keep it different for every website you use it on', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_persistant_object">'.esc_html__('Persistent Connection', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_persistent_object" class="speedycache-custom-checkbox">
							<input type="checkbox" id="speedycache_persistent_object" name="persistent" '. ((!empty($speedycache->object['persistent'])) ? ' checked="true"' : '').'/>
							<div class="speedycache-input-slider"></div>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('This will Keep Alive the connection to redis.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_object_admin">'.esc_html__('Cache WP_Admin', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_object_admin" class="speedycache-custom-checkbox">
							<input type="checkbox" id="speedycache_object_admin" name="admin" '.((!empty($speedycache->object['admin'])) ? ' checked="true"' : '').'/>
							<div class="speedycache-input-slider"></div>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('This will cache the admin pages too.', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_async_flush">'.esc_html__('Asynchronous Flushing', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_async_flush" class="speedycache-custom-checkbox">
							<input type="checkbox" id="speedycache_async_flush" name="async_flush" '.((!empty($speedycache->object['async_flush'])) ? ' checked="true"' : '').'/>
							<div class="speedycache-input-slider"></div>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('Deletes asynchronously, without blocking', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_serialization_method">'.esc_html__('Serialization Method', 'speedycache').'</label></th>
					<td>';
						$serialization_methods = ['SERIALIZER_PHP', 'SERIALIZER_IGBINARY'];

						echo '<label for="speedycache_serialization_method">
						
							<select id="speedycache_serialization_method" name="serialization" value="'. (!empty($speedycache->object['serialization']) ? esc_attr($speedycache->object['serialization']) : 'php').'">
								<option value="none">None</option>';

								foreach($serialization_methods as $method){
									$selected = '';

									if(empty($speedycache->object['serialization']) && $method === 'SERIALIZER_PHP'){
										$selected = 'selected';
									}else if(!empty($speedycache->object['serialization']) && $speedycache->object['serialization'] === $method){
										$selected = 'selected';
									}

									if(defined('Redis::'.$method)){
										echo '<option value="'.esc_attr($method).'" '.esc_attr($selected).'>'.esc_html($method).'</option>';
									}
								}
							echo '</select>
						</label>
						<div class="speedycache-option-desc">'.esc_html('If you don\'t see IG_BINARY option then the phpredis is not built with IG_BINARY, IG_BINARY can save upto 50% space', 'speedycache').'</div>
					</td>
				</tr>

				<tr>
					<th><label for="speedycache_compression_method">'.esc_html__('Compression Method', 'speedycache').'</label>
					</th>
					<td>';
						$serialization_methods = ['None', 'COMPRESSION_ZSTD', 'COMPRESSION_LZ4', 'COMPRESSION_LZF'];

						echo '<label for="speedycache_compression_method">
						
							<select id="speedycache_compression_method" name="compress" value="'. (!empty($speedycache->object['compress']) ? esc_attr($speedycache->object['compress']) : 'php').'">
								<option value="none">None</option>';

								foreach($serialization_methods as $method){
									$selected = '';

									if(empty($speedycache->object['compress']) && $method === 'None'){
										$selected = 'selected';
									}else if(!empty($speedycache->object['compress']) && $speedycache->object['compress'] === $method){
										$selected = 'selected';
									}

									if(defined('Redis::'.$method)){
										echo '<option value="'.esc_attr($method).'" '.esc_attr($selected).'>'.esc_html($method).'</option>';
									}
								}
							echo '</select>
						</label>
						<div class="speedycache-option-desc">'.esc_html('If you dont see any option then your phpredis is not built with compression options', 'speedycache').'</div>
					</td>
				</tr>
				
				<tr>
					<th><label for="speedycache_non_cache_group">'.esc_html__('Do not cache groups', 'speedycache').'</label></th>
					<td>
						<label for="speedycache_non_cache_group">
							<textarea id="speedycache_non_cache_group" name="non_cache_group" rows="5" cols="30">';
								if(empty($speedycache->object['non_cache_group'])){
									$speedycache->object['non_cache_group'] = ['plugins', 'comment', 'counts', 'wc_session_id'];
								}

								foreach($speedycache->object['non_cache_group'] as $group){
									echo esc_html($group) . "\n";
								}
							echo '</textarea>
						</label>
						<div class="speedycache-option-desc">'.esc_html__('These are the groups which should not be cached, One Per Line', 'speedycache').'</div>
					</td>
				</tr>
				
			</table>';

			\SpeedyCache\Settings::save_btn();
			echo '</form>
		</div>';
	}
}
plugin-update-checker.php000064400000151563151526435100011452 0ustar00<?php
/**
 * Plugin Update Checker Library 3.2
 * http://w-shadow.com/
 * 
 * Copyright 2016 Janis Elsts
 * Released under the MIT license. See license.txt for details.
 */

if ( !class_exists('SpeedyCacheUpdateChecker_3_2', false) ):

/**
 * A custom plugin update checker. 
 * 
 * @author Janis Elsts
 * @copyright 2016
 * @version 3.2
 * @access public
 */
#[\AllowDynamicProperties]
class SpeedyCacheUpdateChecker_3_2 {
	public $metadataUrl = ''; //The URL of the plugin's metadata file.
	public $pluginAbsolutePath = ''; //Full path of the main plugin file.
	public $pluginFile = '';  //Plugin filename relative to the plugins directory. Many WP APIs use this to identify plugins.
	public $slug = '';        //Plugin slug.
	public $optionName = '';  //Where to store the update info.
	public $muPluginFile = ''; //For MU plugins, the plugin filename relative to the mu-plugins directory.

	public $debugMode = false; //Set to TRUE to enable error reporting. Errors are raised using trigger_error()
                               //and should be logged to the standard PHP error log.
	public $scheduler;

	protected $upgraderStatus;

	private $debugBarPlugin = null;
	private $cachedInstalledVersion = null;

	private $metadataHost = ''; //The host component of $metadataUrl.

	/**
	 * Class constructor.
	 *
	 * @param string $metadataUrl The URL of the plugin's metadata file.
	 * @param string $pluginFile Fully qualified path to the main plugin file.
	 * @param string $slug The plugin's 'slug'. If not specified, the filename part of $pluginFile sans '.php' will be used as the slug.
	 * @param integer $checkPeriod How often to check for updates (in hours). Defaults to checking every 12 hours. Set to 0 to disable automatic update checks.
	 * @param string $optionName Where to store book-keeping info about update checks. Defaults to 'external_updates-$slug'.
	 * @param string $muPluginFile Optional. The plugin filename relative to the mu-plugins directory.
	 */
	public function __construct($metadataUrl, $pluginFile, $slug = '', $checkPeriod = 12, $optionName = '', $muPluginFile = ''){
		$this->metadataUrl = $metadataUrl;
		$this->pluginAbsolutePath = $pluginFile;
		$this->pluginFile = plugin_basename($this->pluginAbsolutePath);
		$this->muPluginFile = $muPluginFile;
		$this->slug = $slug;
		$this->optionName = $optionName;
		$this->debugMode = (bool)(constant('WP_DEBUG'));

		//If no slug is specified, use the name of the main plugin file as the slug.
		//For example, 'my-cool-plugin/cool-plugin.php' becomes 'cool-plugin'.
		if ( empty($this->slug) ){
			$this->slug = basename($this->pluginFile, '.php');
		}

		//Plugin slugs must be unique.
		$slugCheckFilter = 'puc_is_slug_in_use-' . $this->slug;
		$slugUsedBy = apply_filters($slugCheckFilter, false);
		if ( $slugUsedBy ) {
			$this->triggerError(sprintf(
				'Plugin slug "%s" is already in use by %s. Slugs must be unique.',
				htmlentities($this->slug),
				htmlentities($slugUsedBy)
			), E_USER_ERROR);
		}
		add_filter($slugCheckFilter, array($this, 'getAbsolutePath'));

		
		if ( empty($this->optionName) ){
			$this->optionName = 'external_updates-' . $this->slug;
		}

		//Backwards compatibility: If the plugin is a mu-plugin but no $muPluginFile is specified, assume
		//it's the same as $pluginFile given that it's not in a subdirectory (WP only looks in the base dir).
		if ( (strpbrk($this->pluginFile, '/\\') === false) && $this->isUnknownMuPlugin() ) {
			$this->muPluginFile = $this->pluginFile;
		}

		$this->scheduler = $this->createScheduler($checkPeriod);
		$this->upgraderStatus = new SpeedyCache_PucUpgraderStatus_3_2();

		$this->installHooks();
	}

	/**
	 * Create an instance of the scheduler.
	 *
	 * This is implemented as a method to make it possible for plugins to subclass the update checker
	 * and substitute their own scheduler.
	 *
	 * @param int $checkPeriod
	 * @return SpeedyCache_PucScheduler_3_2
	 */
	protected function createScheduler($checkPeriod) {
		return new SpeedyCache_PucScheduler_3_2($this, $checkPeriod);
	}
	
	/**
	 * Install the hooks required to run periodic update checks and inject update info 
	 * into WP data structures. 
	 * 
	 * @return void
	 */
	protected function installHooks(){
		//Override requests for plugin information
		add_filter('plugins_api', array($this, 'injectInfo'), 20, 3);
		
		//Insert our update info into the update array maintained by WP.
		add_filter('site_transient_update_plugins', array($this,'injectUpdate')); //WP 3.0+
		add_filter('transient_update_plugins', array($this,'injectUpdate')); //WP 2.8+
		add_filter('site_transient_update_plugins', array($this, 'injectTranslationUpdates'));

		add_filter('plugin_row_meta', array($this, 'addCheckForUpdatesLink'), 10, 2);
		add_action('admin_init', array($this, 'handleManualCheck'));
		add_action('all_admin_notices', array($this, 'displayManualCheckResult'));

		//Clear the version number cache when something - anything - is upgraded or WP clears the update cache.
		add_filter('upgrader_post_install', array($this, 'clearCachedVersion'));
		add_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion'));
		//Clear translation updates when WP clears the update cache.
		//This needs to be done directly because the library doesn't actually remove obsolete plugin updates,
		//it just hides them (see getUpdate()). We can't do that with translations - too much disk I/O.
		add_action('delete_site_transient_update_plugins', array($this, 'clearCachedTranslationUpdates'));

		if ( did_action('plugins_loaded') ) {
			$this->initDebugBarPanel();
		} else {
			add_action('plugins_loaded', array($this, 'initDebugBarPanel'));
		}

		//Rename the update directory to be the same as the existing directory.
		add_filter('upgrader_source_selection', array($this, 'fixDirectoryName'), 10, 3);

		//Enable language support (i18n).
		load_plugin_textdomain('plugin-update-checker', false, plugin_basename(dirname(__FILE__)) . '/languages');

		//Allow HTTP requests to the metadata URL even if it's on a local host.
		$this->metadataHost = @parse_url($this->metadataUrl, PHP_URL_HOST);
		add_filter('http_request_host_is_external', array($this, 'allowMetadataHost'), 10, 2);
	}
	
	/**
	 * Explicitly allow HTTP requests to the metadata URL.
	 *
	 * WordPress has a security feature where the HTTP API will reject all requests that are sent to
	 * another site hosted on the same server as the current site (IP match), a local host, or a local
	 * IP, unless the host exactly matches the current site.
	 *
	 * This feature is opt-in (at least in WP 4.4). Apparently some people enable it.
	 *
	 * That can be a problem when you're developing your plugin and you decide to host the update information
	 * on the same server as your test site. Update requests will mysteriously fail.
	 *
	 * We fix that by adding an exception for the metadata host.
	 *
	 * @param bool $allow
	 * @param string $host
	 * @return bool
	 */
	public function allowMetadataHost($allow, $host) {
		if ( strtolower($host) === strtolower($this->metadataHost) ) {
			return true;
		}
		return $allow;
	}

	/**
	 * Retrieve plugin info from the configured API endpoint.
	 * 
	 * @uses wp_remote_get()
	 * 
	 * @param array $queryArgs Additional query arguments to append to the request. Optional.
	 * @return SpeedyCacheInfo_3_2
	 */
	public function requestInfo($queryArgs = array()){
		//Query args to append to the URL. Plugins can add their own by using a filter callback (see addQueryArgFilter()).
		$installedVersion = $this->getInstalledVersion();
		$queryArgs['installed_version'] = ($installedVersion !== null) ? $installedVersion : '';
		$queryArgs = apply_filters('puc_request_info_query_args-'.$this->slug, $queryArgs);
		
		//Various options for the wp_remote_get() call. Plugins can filter these, too.
		$options = array(
			'timeout' => 10, //seconds
			'headers' => array(
				'Accept' => 'application/json'
			),
		);
		$options = apply_filters('puc_request_info_options-'.$this->slug, $options);
		
		//The plugin info should be at 'http://your-api.com/url/here/$slug/info.json'
		$url = $this->metadataUrl; 
		if ( !empty($queryArgs) ){
			$url = add_query_arg($queryArgs, $url);
		}
		
		$result = wp_remote_get(
			$url,
			$options
		);

		//Try to parse the response
		$status = $this->validateApiResponse($result);
		$pluginInfo = null;
		if ( !is_wp_error($status) ){
			$pluginInfo = SpeedyCacheInfo_3_2::fromJson($result['body']);
			if ( $pluginInfo !== null ) {
				$pluginInfo->filename = $this->pluginFile;
				$pluginInfo->slug = $this->slug;
			}
		} else {
			$this->triggerError(
				sprintf('The URL %s does not point to a valid plugin metadata file. ', $url)
					. $status->get_error_message(),
				E_USER_WARNING
			);
		}

		$pluginInfo = apply_filters('puc_request_info_result-'.$this->slug, $pluginInfo, $result);
		return $pluginInfo;
	}

	/**
	 * Check if $result is a successful update API response.
	 *
	 * @param array|WP_Error $result
	 * @return true|WP_Error
	 */
	private function validateApiResponse($result) {
		if ( is_wp_error($result) ) { /** @var WP_Error $result */
			return new WP_Error($result->get_error_code(), 'WP HTTP Error: ' . $result->get_error_message());
		}

		if ( !isset($result['response']['code']) ) {
			return new WP_Error('puc_no_response_code', 'wp_remote_get() returned an unexpected result.');
		}

		if ( $result['response']['code'] !== 200 ) {
			return new WP_Error(
				'puc_unexpected_response_code',
				'HTTP response code is ' . $result['response']['code'] . ' (expected: 200)'
			);
		}

		if ( empty($result['body']) ) {
			return new WP_Error('puc_empty_response', 'The metadata file appears to be empty.');
		}

		return true;
	}

	/**
	 * Retrieve the latest update (if any) from the configured API endpoint.
	 *
	 * @uses SpeedyCacheUpdateChecker::requestInfo()
	 *
	 * @return SpeedyCacheUpdate_3_2 An instance of SpeedyCacheUpdate, or NULL when no updates are available.
	 */
	public function requestUpdate(){
		//For the sake of simplicity, this function just calls requestInfo() 
		//and transforms the result accordingly.
		$pluginInfo = $this->requestInfo(array('checking_for_updates' => '1'));
		if ( $pluginInfo == null ){
			return null;
		}
		$update = SpeedyCacheUpdate_3_2::fromSpeedyCacheInfo($pluginInfo);

		//Keep only those translation updates that apply to this site.
		$update->translations = $this->filterApplicableTranslations($update->translations);

		return $update;
	}

	/**
	 * Filter a list of translation updates and return a new list that contains only updates
	 * that apply to the current site.
	 *
	 * @param array $translations
	 * @return array
	 */
	private function filterApplicableTranslations($translations) {
		$languages = array_flip(array_values(get_available_languages()));
		$installedTranslations = wp_get_installed_translations('plugins');
		if ( isset($installedTranslations[$this->slug]) ) {
			$installedTranslations = $installedTranslations[$this->slug];
		} else {
			$installedTranslations = array();
		}

		$applicableTranslations = array();
		foreach($translations as $translation) {
			//Does it match one of the available core languages?
			$isApplicable = array_key_exists($translation->language, $languages);
			//Is it more recent than an already-installed translation?
			if ( isset($installedTranslations[$translation->language]) ) {
				$updateTimestamp = strtotime($translation->updated);
				$installedTimestamp = strtotime($installedTranslations[$translation->language]['PO-Revision-Date']);
				$isApplicable = $updateTimestamp > $installedTimestamp;
			}

			if ( $isApplicable ) {
				$applicableTranslations[] = $translation;
			}
		}

		return $applicableTranslations;
	}
	
	/**
	 * Get the currently installed version of the plugin.
	 * 
	 * @return string Version number.
	 */
	public function getInstalledVersion(){
		if ( isset($this->cachedInstalledVersion) ) {
			return $this->cachedInstalledVersion;
		}

		$pluginHeader = $this->getPluginHeader();
		if ( isset($pluginHeader['Version']) ) {
			$this->cachedInstalledVersion = $pluginHeader['Version'];
			return $pluginHeader['Version'];
		} else {
			//This can happen if the filename points to something that is not a plugin.
			$this->triggerError(
				sprintf(
					"Can't to read the Version header for '%s'. The filename is incorrect or is not a plugin.",
					$this->pluginFile
				),
				E_USER_WARNING
			);
			return null;
		}
	}

	/**
	 * Get plugin's metadata from its file header.
	 *
	 * @return array
	 */
	protected function getPluginHeader() {
		if ( !is_file($this->pluginAbsolutePath) ) {
			//This can happen if the plugin filename is wrong.
			$this->triggerError(
				sprintf(
					"Can't to read the plugin header for '%s'. The file does not exist.",
					$this->pluginFile
				),
				E_USER_WARNING
			);
			return array();
		}

		if ( !function_exists('get_plugin_data') ){
			/** @noinspection PhpIncludeInspection */
			require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
		}
		return get_plugin_data($this->pluginAbsolutePath, false, false);
	}

	/**
	 * Check for plugin updates.
	 * The results are stored in the DB option specified in $optionName.
	 *
	 * @return SpeedyCacheUpdate_3_2|null
	 */
	public function checkForUpdates(){
		$installedVersion = $this->getInstalledVersion();
		//Fail silently if we can't find the plugin or read its header.
		if ( $installedVersion === null ) {
			$this->triggerError(
				sprintf('Skipping update check for %s - installed version unknown.', $this->pluginFile),
				E_USER_WARNING
			);
			return null;
		}

		$state = $this->getUpdateState();
		if ( empty($state) ){
			$state = new stdClass;
			$state->lastCheck = 0;
			$state->checkedVersion = '';
			$state->update = null;
		}
		
		$state->lastCheck = time();
		$state->checkedVersion = $installedVersion;
		$this->setUpdateState($state); //Save before checking in case something goes wrong 
		
		$state->update = $this->requestUpdate();
		$this->setUpdateState($state);

		return $this->getUpdate();
	}
	
	/**
	 * Load the update checker state from the DB.
	 *  
	 * @return stdClass|null
	 */
	public function getUpdateState() {
		$state = get_site_option($this->optionName, null);
		if ( empty($state) || !is_object($state)) {
			$state = null;
		}

		if ( isset($state, $state->update) && is_object($state->update) ) {
			$state->update = SpeedyCacheUpdate_3_2::fromObject($state->update);
		}
		return $state;
	}
	
	
	/**
	 * Persist the update checker state to the DB.
	 * 
	 * @param StdClass $state
	 * @return void
	 */
	private function setUpdateState($state) {
		if ( isset($state->update) && is_object($state->update) && method_exists($state->update, 'toStdClass') ) {
			$update = $state->update; /** @var SpeedyCacheUpdate_3_2 $update */
			$state->update = $update->toStdClass();
		}
		update_site_option($this->optionName, $state);
	}

	/**
	 * Reset update checker state - i.e. last check time, cached update data and so on.
	 *
	 * Call this when your plugin is being uninstalled, or if you want to
	 * clear the update cache.
	 */
	public function resetUpdateState() {
		delete_site_option($this->optionName);
	}
	
	/**
	 * Intercept plugins_api() calls that request information about our plugin and 
	 * use the configured API endpoint to satisfy them. 
	 * 
	 * @see plugins_api()
	 * 
	 * @param mixed $result
	 * @param string $action
	 * @param array|object $args
	 * @return mixed
	 */
	public function injectInfo($result, $action = null, $args = null){
    	$relevant = ($action == 'plugin_information') && isset($args->slug) && (
			($args->slug == $this->slug) || ($args->slug == dirname($this->pluginFile))
		);
		if ( !$relevant ) {
			return $result;
		}
		
		$pluginInfo = $this->requestInfo();
		$pluginInfo = apply_filters('puc_pre_inject_info-' . $this->slug, $pluginInfo);
		if ( $pluginInfo ) {
			return $pluginInfo->toWpFormat();
		}
				
		return $result;
	}
	
	/**
	 * Insert the latest update (if any) into the update list maintained by WP.
	 * 
	 * @param StdClass $updates Update list.
	 * @return StdClass Modified update list.
	 */
	public function injectUpdate($updates){
		//Is there an update to insert?
		$update = $this->getUpdate();

		//No update notifications for mu-plugins unless explicitly enabled. The MU plugin file
		//is usually different from the main plugin file so the update wouldn't show up properly anyway.
		if ( $this->isUnknownMuPlugin() ) {
			$update = null;
		}

		if ( !empty($update) ) {
			//Let plugins filter the update info before it's passed on to WordPress.
			$update = apply_filters('puc_pre_inject_update-' . $this->slug, $update);
			$updates = $this->addUpdateToList($updates, $update);
		} else {
			//Clean up any stale update info.
			$updates = $this->removeUpdateFromList($updates);
		}

		return $updates;
	}

	/**
	 * @param StdClass|null $updates
	 * @param SpeedyCacheUpdate_3_2 $updateToAdd
	 * @return StdClass
	 */
	private function addUpdateToList($updates, $updateToAdd) {
		if ( !is_object($updates) ) {
			$updates = new stdClass();
			$updates->response = array();
		}

		$wpUpdate = $updateToAdd->toWpFormat();
		$pluginFile = $this->pluginFile;

		if ( $this->isMuPlugin() ) {
			//WP does not support automatic update installation for mu-plugins, but we can still display a notice.
			$wpUpdate->package = null;
			$pluginFile = $this->muPluginFile;
		}
		$updates->response[$pluginFile] = $wpUpdate;
		return $updates;
	}

	/**
	 * @param stdClass|null $updates
	 * @return stdClass|null
	 */
	private function removeUpdateFromList($updates) {
		if ( isset($updates, $updates->response) ) {
			unset($updates->response[$this->pluginFile]);
			if ( !empty($this->muPluginFile) ) {
				unset($updates->response[$this->muPluginFile]);
			}
		}
		return $updates;
	}

	/**
	 * Insert translation updates into the list maintained by WordPress.
	 *
	 * @param stdClass $updates
	 * @return stdClass
	 */
	public function injectTranslationUpdates($updates) {
		$translationUpdates = $this->getTranslationUpdates();
		if ( empty($translationUpdates) ) {
			return $updates;
		}

		//Being defensive.
		if ( !is_object($updates) ) {
			$updates = new stdClass();
		}
		if ( !isset($updates->translations) ) {
			$updates->translations = array();
		}

		//In case there's a name collision with a plugin hosted on wordpress.org,
		//remove any preexisting updates that match our plugin.
		$translationType = 'plugin';
		$filteredTranslations = array();
		foreach($updates->translations as $translation) {
			if ( ($translation['type'] === $translationType) && ($translation['slug'] === $this->slug) ) {
				continue;
			}
			$filteredTranslations[] = $translation;
		}
		$updates->translations = $filteredTranslations;

		//Add our updates to the list.
		foreach($translationUpdates as $update) {
			$convertedUpdate = array_merge(
				array(
					'type' => $translationType,
					'slug' => $this->slug,
					'autoupdate' => 0,
					//AFAICT, WordPress doesn't actually use the "version" field for anything.
					//But lets make sure it's there, just in case.
					'version' => isset($update->version) ? $update->version : ('1.' . strtotime($update->updated)),
				),
				(array)$update
			);

			$updates->translations[] = $convertedUpdate;
		}

		return $updates;
	}

	/**
	 * Rename the update directory to match the existing plugin directory.
	 *
	 * When WordPress installs a plugin or theme update, it assumes that the ZIP file will contain
	 * exactly one directory, and that the directory name will be the same as the directory where
	 * the plugin/theme is currently installed.
	 *
	 * GitHub and other repositories provide ZIP downloads, but they often use directory names like
	 * "project-branch" or "project-tag-hash". We need to change the name to the actual plugin folder.
	 *
	 * This is a hook callback. Don't call it from a plugin.
	 *
	 * @param string $source The directory to copy to /wp-content/plugins. Usually a subdirectory of $remoteSource.
	 * @param string $remoteSource WordPress has extracted the update to this directory.
	 * @param WP_Upgrader $upgrader
	 * @return string|WP_Error
	 */
	public function fixDirectoryName($source, $remoteSource, $upgrader) {
		global $wp_filesystem; /** @var WP_Filesystem_Base $wp_filesystem */

		//Basic sanity checks.
		if ( !isset($source, $remoteSource, $upgrader, $upgrader->skin, $wp_filesystem) ) {
			return $source;
		}

		//If WordPress is upgrading anything other than our plugin, leave the directory name unchanged.
		if ( !$this->isPluginBeingUpgraded($upgrader) ) {
			return $source;
		}

		//Rename the source to match the existing plugin directory.
		$pluginDirectoryName = dirname($this->pluginFile);
		if ( $pluginDirectoryName === '.' ) {
			return $source;
		}
		$correctedSource = trailingslashit($remoteSource) . $pluginDirectoryName . '/';
		if ( $source !== $correctedSource ) {
			//The update archive should contain a single directory that contains the rest of plugin files. Otherwise,
			//WordPress will try to copy the entire working directory ($source == $remoteSource). We can't rename
			//$remoteSource because that would break WordPress code that cleans up temporary files after update.
			if ( $this->isBadDirectoryStructure($remoteSource) ) {
				return new WP_Error(
					'puc-incorrect-directory-structure',
					sprintf(
						'The directory structure of the update is incorrect. All plugin files should be inside ' .
						'a directory named <span class="code">%s</span>, not at the root of the ZIP file.',
						htmlentities($this->slug)
					)
				);
			}

			/** @var WP_Upgrader_Skin $upgrader->skin */
			$upgrader->skin->feedback(sprintf(
				'Renaming %s to %s&#8230;',
				'<span class="code">' . basename($source) . '</span>',
				'<span class="code">' . $pluginDirectoryName . '</span>'
			));

			if ( $wp_filesystem->move($source, $correctedSource, true) ) {
				$upgrader->skin->feedback('Plugin directory successfully renamed.');
				return $correctedSource;
			} else {
				return new WP_Error(
					'puc-rename-failed',
					'Unable to rename the update to match the existing plugin directory.'
				);
			}
		}

		return $source;
	}

	/**
	 * Check for incorrect update directory structure. An update must contain a single directory,
	 * all other files should be inside that directory.
	 *
	 * @param string $remoteSource Directory path.
	 * @return bool
	 */
	private function isBadDirectoryStructure($remoteSource) {
		global $wp_filesystem; /** @var WP_Filesystem_Base $wp_filesystem */

		$sourceFiles = $wp_filesystem->dirlist($remoteSource);
		if ( is_array($sourceFiles) ) {
			$sourceFiles = array_keys($sourceFiles);
			$firstFilePath = trailingslashit($remoteSource) . $sourceFiles[0];
			return (count($sourceFiles) > 1) || (!$wp_filesystem->is_dir($firstFilePath));
		}

		//Assume it's fine.
		return false;
	}

	/**
	 * Is there and update being installed RIGHT NOW, for this specific plugin?
	 *
	 * @param WP_Upgrader|null $upgrader The upgrader that's performing the current update.
	 * @return bool
	 */
	public function isPluginBeingUpgraded($upgrader = null) {
		return $this->upgraderStatus->isPluginBeingUpgraded($this->pluginFile, $upgrader);
	}

	/**
	 * Get the details of the currently available update, if any.
	 *
	 * If no updates are available, or if the last known update version is below or equal
	 * to the currently installed version, this method will return NULL.
	 *
	 * Uses cached update data. To retrieve update information straight from
	 * the metadata URL, call requestUpdate() instead.
	 *
	 * @return SpeedyCacheUpdate_3_2|null
	 */
	public function getUpdate() {
		$state = $this->getUpdateState(); /** @var StdClass $state */

		//Is there an update available?
		if ( isset($state, $state->update) ) {
			$update = $state->update;
			//Check if the update is actually newer than the currently installed version.
			$installedVersion = $this->getInstalledVersion();
			if ( ($installedVersion !== null) && version_compare($update->version, $installedVersion, '>') ){
				$update->filename = $this->pluginFile;
				return $update;
			}
		}
		return null;
	}

	/**
	 * Get a list of available translation updates.
	 *
	 * This method will return an empty array if there are no updates.
	 * Uses cached update data.
	 *
	 * @return array
	 */
	public function getTranslationUpdates() {
		$state = $this->getUpdateState();
		if ( isset($state, $state->update, $state->update->translations) ) {
			return $state->update->translations;
		}
		return array();
	}

	/**
	 * Remove all cached translation updates.
	 *
	 * @see wp_clean_update_cache
	 */
	public function clearCachedTranslationUpdates() {
		$state = $this->getUpdateState();
		if ( isset($state, $state->update, $state->update->translations) ) {
			$state->update->translations = array();
			$this->setUpdateState($state);
		}
	}

	/**
	 * Add a "Check for updates" link to the plugin row in the "Plugins" page. By default,
	 * the new link will appear after the "Visit plugin site" link.
	 *
	 * You can change the link text by using the "puc_manual_check_link-$slug" filter.
	 * Returning an empty string from the filter will disable the link.
	 *
	 * @param array $pluginMeta Array of meta links.
	 * @param string $pluginFile
	 * @return array
	 */
	public function addCheckForUpdatesLink($pluginMeta, $pluginFile) {
		$isRelevant = ($pluginFile == $this->pluginFile)
		              || (!empty($this->muPluginFile) && $pluginFile == $this->muPluginFile);

		if ( $isRelevant && current_user_can('update_plugins') ) {
			$linkUrl = wp_nonce_url(
				add_query_arg(
					array(
						'puc_check_for_updates' => 1,
						'puc_slug' => $this->slug,
					),
					self_admin_url('plugins.php')
				),
				'puc_check_for_updates'
			);

			$linkText = apply_filters('puc_manual_check_link-' . $this->slug, __('Check for updates', 'plugin-update-checker'));
			if ( !empty($linkText) ) {
				$final_link = sprintf('<a href="%s">%s</a>', esc_attr($linkUrl), $linkText);
				$pluginMeta[] = apply_filters('puc_manual_final_check_link-' . $this->slug, $final_link);
			}
		}
		return $pluginMeta;
	}

	/**
	 * Check for updates when the user clicks the "Check for updates" link.
	 * @see self::addCheckForUpdatesLink()
	 *
	 * @return void
	 */
	public function handleManualCheck() {
		$shouldCheck =
			   isset($_GET['puc_check_for_updates'], $_GET['puc_slug'])
			&& $_GET['puc_slug'] == $this->slug
			&& current_user_can('update_plugins')
			&& check_admin_referer('puc_check_for_updates');

		if ( $shouldCheck ) {
			$update = $this->checkForUpdates();
			$status = ($update === null) ? 'no_update' : 'update_available';
			wp_redirect(add_query_arg(
				array(
					'puc_update_check_result' => $status,
					'puc_slug' => $this->slug,
				),
				self_admin_url('plugins.php')
			));
		}
	}

	/**
	 * Display the results of a manual update check.
	 * @see self::handleManualCheck()
	 *
	 * You can change the result message by using the "puc_manual_check_message-$slug" filter.
	 */
	public function displayManualCheckResult() {
		if ( isset($_GET['puc_update_check_result'], $_GET['puc_slug']) && ($_GET['puc_slug'] == $this->slug) ) {
			$status = strval($_GET['puc_update_check_result']);
			if ( $status == 'no_update' ) {
				$message = __('This plugin is up to date.', 'plugin-update-checker');
			} else if ( $status == 'update_available' ) {
				$message = __('A new version of this plugin is available.', 'plugin-update-checker');
			} else {
				$message = sprintf(__('Unknown update checker status "%s"', 'plugin-update-checker'), htmlentities($status));
			}
			printf(
				'<div class="updated notice is-dismissible"><p>%s</p></div>',
				apply_filters('puc_manual_check_message-' . $this->slug, $message, $status)
			);
		}
	}

	/**
	 * Check if the plugin file is inside the mu-plugins directory.
	 *
	 * @return bool
	 */
	protected function isMuPlugin() {
		static $cachedResult = null;

		if ( $cachedResult === null ) {
			//Convert both paths to the canonical form before comparison.
			$muPluginDir = realpath(WPMU_PLUGIN_DIR);
			$pluginPath  = realpath($this->pluginAbsolutePath);
			
			if(!empty($muPluginDir)){
				$cachedResult = (strpos($pluginPath, $muPluginDir) === 0);
			}else{
				$cachedResult = false;
			}
		}

		return $cachedResult;
	}

	/**
	 * MU plugins are partially supported, but only when we know which file in mu-plugins
	 * corresponds to this plugin.
	 *
	 * @return bool
	 */
	protected function isUnknownMuPlugin() {
		return empty($this->muPluginFile) && $this->isMuPlugin();
	}

	/**
	 * Clear the cached plugin version. This method can be set up as a filter (hook) and will
	 * return the filter argument unmodified.
	 *
	 * @param mixed $filterArgument
	 * @return mixed
	 */
	public function clearCachedVersion($filterArgument = null) {
		$this->cachedInstalledVersion = null;
		return $filterArgument;
	}

	/**
	 * Get absolute path to the main plugin file.
	 *
	 * @return string
	 */
	public function getAbsolutePath() {
		return $this->pluginAbsolutePath;
	}

	/**
	 * Register a callback for filtering query arguments. 
	 * 
	 * The callback function should take one argument - an associative array of query arguments.
	 * It should return a modified array of query arguments.
	 * 
	 * @uses add_filter() This method is a convenience wrapper for add_filter().
	 * 
	 * @param callable $callback
	 * @return void
	 */
	public function addQueryArgFilter($callback){
		add_filter('puc_request_info_query_args-'.$this->slug, $callback);
	}
	
	/**
	 * Register a callback for filtering arguments passed to wp_remote_get().
	 * 
	 * The callback function should take one argument - an associative array of arguments -
	 * and return a modified array or arguments. See the WP documentation on wp_remote_get()
	 * for details on what arguments are available and how they work. 
	 * 
	 * @uses add_filter() This method is a convenience wrapper for add_filter().
	 * 
	 * @param callable $callback
	 * @return void
	 */
	public function addHttpRequestArgFilter($callback){
		add_filter('puc_request_info_options-'.$this->slug, $callback);
	}
	
	/**
	 * Register a callback for filtering the plugin info retrieved from the external API.
	 * 
	 * The callback function should take two arguments. If the plugin info was retrieved 
	 * successfully, the first argument passed will be an instance of  SpeedyCacheInfo. Otherwise, 
	 * it will be NULL. The second argument will be the corresponding return value of 
	 * wp_remote_get (see WP docs for details).
	 *  
	 * The callback function should return a new or modified instance of SpeedyCacheInfo or NULL.
	 * 
	 * @uses add_filter() This method is a convenience wrapper for add_filter().
	 * 
	 * @param callable $callback
	 * @return void
	 */
	public function addResultFilter($callback){
		add_filter('puc_request_info_result-'.$this->slug, $callback, 10, 2);
	}

	/**
	 * Register a callback for one of the update checker filters.
	 *
	 * Identical to add_filter(), except it automatically adds the "puc_" prefix
	 * and the "-$plugin_slug" suffix to the filter name. For example, "request_info_result"
	 * becomes "puc_request_info_result-your_plugin_slug".
	 *
	 * @param string $tag
	 * @param callable $callback
	 * @param int $priority
	 * @param int $acceptedArgs
	 */
	public function addFilter($tag, $callback, $priority = 10, $acceptedArgs = 1) {
		add_filter('puc_' . $tag . '-' . $this->slug, $callback, $priority, $acceptedArgs);
	}

	/**
	 * Initialize the update checker Debug Bar plugin/add-on thingy.
	 */
	public function initDebugBarPanel() {
		$debugBarPlugin = dirname(__FILE__) . '/debug-bar-plugin.php';
		if ( class_exists('Debug_Bar', false) && file_exists($debugBarPlugin) ) {
			/** @noinspection PhpIncludeInspection */
			require_once $debugBarPlugin;
			$this->debugBarPlugin = new SpeedyCache_PucDebugBarPlugin_3_2($this);
		}
	}

	/**
	 * Trigger a PHP error, but only when $debugMode is enabled.
	 *
	 * @param string $message
	 * @param int $errorType
	 */
	protected function triggerError($message, $errorType) {
		if ( $this->debugMode ) {
			trigger_error($message, $errorType);
		}
	}
}

endif;

if ( !class_exists('SpeedyCacheInfo_3_2', false) ):

/**
 * A container class for holding and transforming various plugin metadata.
 * 
 * @author Janis Elsts
 * @copyright 2016
 * @version 3.2
 * @access public
 */
#[\AllowDynamicProperties]
class SpeedyCacheInfo_3_2 {
	//Most fields map directly to the contents of the plugin's info.json file.
	//See the relevant docs for a description of their meaning.  
	public $name;
	public $slug;
	public $version;
	public $homepage;
	public $sections = array();
	public $banners;
	public $translations = array();
	public $download_url;

	public $author;
	public $author_homepage;
	
	public $requires;
	public $tested;
	public $upgrade_notice;
	
	public $rating;
	public $num_ratings;
	public $downloaded;
	public $active_installs;
	public $last_updated;
	
	public $id = 0; //The native WP.org API returns numeric plugin IDs, but they're not used for anything.

	public $filename; //Plugin filename relative to the plugins directory.
		
	/**
	 * Create a new instance of SpeedyCacheInfo from JSON-encoded plugin info 
	 * returned by an external update API.
	 * 
	 * @param string $json Valid JSON string representing plugin info.
	 * @return SpeedyCacheInfo_3_2|null New instance of SpeedyCacheInfo, or NULL on error.
	 */
	public static function fromJson($json){
		/** @var StdClass $apiResponse */
		$apiResponse = json_decode($json);
		if ( empty($apiResponse) || !is_object($apiResponse) ){
			trigger_error(
				"Failed to parse plugin metadata. Try validating your .json file with http://jsonlint.com/",
				E_USER_NOTICE
			);
			return null;
		}
		
		$valid = self::validateMetadata($apiResponse);
		if ( is_wp_error($valid) ){
			trigger_error($valid->get_error_message(), E_USER_NOTICE);
			return null;
		}
		
		$info = new self();
		foreach(get_object_vars($apiResponse) as $key => $value){
			$info->$key = $value;
		}

		//json_decode decodes assoc. arrays as objects. We want it as an array.
		$info->sections = (array)$info->sections;
		
		return $info;		
	}

	/**
	 * Very, very basic validation.
	 *
	 * @param StdClass $apiResponse
	 * @return bool|WP_Error
	 */
	protected static function validateMetadata($apiResponse) {
		if (
			!isset($apiResponse->name, $apiResponse->version)
			|| empty($apiResponse->name)
			|| empty($apiResponse->version)
		) {
			return new WP_Error(
				'puc-invalid-metadata',
				"The plugin metadata file does not contain the required 'name' and/or 'version' keys."
			);
		}
		return true;
	}

	
	/**
	 * Transform plugin info into the format used by the native WordPress.org API
	 * 
	 * @return object
	 */
	public function toWpFormat(){
		$info = new stdClass;
		
		//The custom update API is built so that many fields have the same name and format
		//as those returned by the native WordPress.org API. These can be assigned directly. 
		$sameFormat = array(
			'name', 'slug', 'version', 'requires', 'tested', 'rating', 'upgrade_notice',
			'num_ratings', 'downloaded', 'active_installs', 'homepage', 'last_updated',
		);
		foreach($sameFormat as $field){
			if ( isset($this->$field) ) {
				$info->$field = $this->$field;
			} else {
				$info->$field = null;
			}
		}

		//Other fields need to be renamed and/or transformed.
		$info->download_link = $this->download_url;
		$info->author = $this->getFormattedAuthor();
		$info->sections = array_merge(array('description' => ''), $this->sections);

		if ( !empty($this->banners) ) {
			//WP expects an array with two keys: "high" and "low". Both are optional.
			//Docs: https://wordpress.org/plugins/about/faq/#banners
			$info->banners = is_object($this->banners) ? get_object_vars($this->banners) : $this->banners;
			$info->banners = array_intersect_key($info->banners, array('high' => true, 'low' => true));
		}

		return $info;
	}

	protected function getFormattedAuthor() {
		if ( !empty($this->author_homepage) ){
			return sprintf('<a href="%s">%s</a>', $this->author_homepage, $this->author);
		}
		return $this->author;
	}
}
	
endif;

if ( !class_exists('SpeedyCacheUpdate_3_2', false) ):

/**
 * A simple container class for holding information about an available update.
 * 
 * @author Janis Elsts
 * @copyright 2016
 * @version 3.2
 * @access public
 */
#[\AllowDynamicProperties]
class SpeedyCacheUpdate_3_2 {
	public $id = 0;
	public $slug;
	public $version;
	public $homepage;
	public $download_url;
	public $upgrade_notice;
	public $tested;
	public $translations = array();
	public $filename; //Plugin filename relative to the plugins directory.

	private static $fields = array(
		'id', 'slug', 'version', 'homepage', 'tested',
		'download_url', 'upgrade_notice', 'filename',
		'translations'
	);
	
	/**
	 * Create a new instance of SpeedyCacheUpdate from its JSON-encoded representation.
	 * 
	 * @param string $json
	 * @return SpeedyCacheUpdate_3_2|null
	 */
	public static function fromJson($json){
		//Since update-related information is simply a subset of the full plugin info,
		//we can parse the update JSON as if it was a plugin info string, then copy over
		//the parts that we care about.
		$pluginInfo = SpeedyCacheInfo_3_2::fromJson($json);
		if ( $pluginInfo != null ) {
			return self::fromSpeedyCacheInfo($pluginInfo);
		} else {
			return null;
		}
	}

	/**
	 * Create a new instance of SpeedyCacheUpdate based on an instance of SpeedyCacheInfo.
	 * Basically, this just copies a subset of fields from one object to another.
	 * 
	 * @param SpeedyCacheInfo_3_2 $info
	 * @return SpeedyCacheUpdate_3_2
	 */
	public static function fromSpeedyCacheInfo($info){
		return self::fromObject($info);
	}
	
	/**
	 * Create a new instance of SpeedyCacheUpdate by copying the necessary fields from 
	 * another object.
	 *  
	 * @param StdClass|SpeedyCacheInfo_3_2|SpeedyCacheUpdate_3_2 $object The source object.
	 * @return SpeedyCacheUpdate_3_2 The new copy.
	 */
	public static function fromObject($object) {
		$update = new self();
		$fields = self::$fields;
		if ( !empty($object->slug) ) {
			$fields = apply_filters('puc_retain_fields-' . $object->slug, $fields);
		}
		foreach($fields as $field){
			if (property_exists($object, $field)) {
				$update->$field = $object->$field;
			}
		}
		return $update;
	}
	
	/**
	 * Create an instance of StdClass that can later be converted back to 
	 * a SpeedyCacheUpdate. Useful for serialization and caching, as it avoids
	 * the "incomplete object" problem if the cached value is loaded before
	 * this class.
	 * 
	 * @return StdClass
	 */
	public function toStdClass() {
		$object = new stdClass();
		$fields = self::$fields;
		if ( !empty($this->slug) ) {
			$fields = apply_filters('puc_retain_fields-' . $this->slug, $fields);
		}
		foreach($fields as $field){
			if (property_exists($this, $field)) {
				$object->$field = $this->$field;
			}
		}
		return $object;
	}
	
	
	/**
	 * Transform the update into the format used by WordPress native plugin API.
	 * 
	 * @return object
	 */
	public function toWpFormat(){
		$update = new stdClass;

		$update->id = $this->id;
		$update->slug = $this->slug;
		$update->new_version = $this->version;
		$update->url = $this->homepage;
		$update->package = $this->download_url;
		$update->tested = $this->tested;
		$update->plugin = $this->filename;

		if ( !empty($this->upgrade_notice) ){
			$update->upgrade_notice = $this->upgrade_notice;
		}
		
		return $update;
	}
}
	
endif;

if ( !class_exists('SpeedyCache_PucScheduler_3_2', false) ):

/**
 * The scheduler decides when and how often to check for updates.
 * It calls @see SpeedyCacheUpdateChecker::checkForUpdates() to perform the actual checks.
 *
 * @version 3.2
 */
#[\AllowDynamicProperties]
class SpeedyCache_PucScheduler_3_2 {
	public $checkPeriod = 12; //How often to check for updates (in hours).
	public $throttleRedundantChecks = false; //Check less often if we already know that an update is available.
	public $throttledCheckPeriod = 72;

	/**
	 * @var SpeedyCacheUpdateChecker_3_2
	 */
	protected $updateChecker;

	private $cronHook = null;

	/**
	 * Scheduler constructor.
	 *
	 * @param SpeedyCacheUpdateChecker_3_2 $updateChecker
	 * @param int $checkPeriod How often to check for updates (in hours).
	 */
	public function __construct($updateChecker, $checkPeriod) {
		$this->updateChecker = $updateChecker;
		$this->checkPeriod = $checkPeriod;

		//Set up the periodic update checks
		$this->cronHook = 'check_plugin_updates-' . $this->updateChecker->slug;
		if ( $this->checkPeriod > 0 ){

			//Trigger the check via Cron.
			//Try to use one of the default schedules if possible as it's less likely to conflict
			//with other plugins and their custom schedules.
			$defaultSchedules = array(
				1  => 'hourly',
				12 => 'twicedaily',
				24 => 'daily',
			);
			if ( array_key_exists($this->checkPeriod, $defaultSchedules) ) {
				$scheduleName = $defaultSchedules[$this->checkPeriod];
			} else {
				//Use a custom cron schedule.
				$scheduleName = 'every' . $this->checkPeriod . 'hours';
				add_filter('cron_schedules', array($this, '_addCustomSchedule'));
			}

			if ( !wp_next_scheduled($this->cronHook) && !defined('WP_INSTALLING') ) {
				wp_schedule_event(time(), $scheduleName, $this->cronHook);
			}
			add_action($this->cronHook, array($this, 'maybeCheckForUpdates'));

			register_deactivation_hook($this->updateChecker->pluginFile, array($this, '_removeUpdaterCron'));

			//In case Cron is disabled or unreliable, we also manually trigger
			//the periodic checks while the user is browsing the Dashboard.
			add_action( 'admin_init', array($this, 'maybeCheckForUpdates') );

			//Like WordPress itself, we check more often on certain pages.
			/** @see wp_update_plugins */
			add_action('load-update-core.php', array($this, 'maybeCheckForUpdates'));
			add_action('load-plugins.php', array($this, 'maybeCheckForUpdates'));
			add_action('load-update.php', array($this, 'maybeCheckForUpdates'));
			//This hook fires after a bulk update is complete.
			add_action('upgrader_process_complete', array($this, 'maybeCheckForUpdates'), 11, 0);

		} else {
			//Periodic checks are disabled.
			wp_clear_scheduled_hook($this->cronHook);
		}
	}

	/**
	 * Check for updates if the configured check interval has already elapsed.
	 * Will use a shorter check interval on certain admin pages like "Dashboard -> Updates" or when doing cron.
	 *
	 * You can override the default behaviour by using the "puc_check_now-$slug" filter.
	 * The filter callback will be passed three parameters:
	 *     - Current decision. TRUE = check updates now, FALSE = don't check now.
	 *     - Last check time as a Unix timestamp.
	 *     - Configured check period in hours.
	 * Return TRUE to check for updates immediately, or FALSE to cancel.
	 *
	 * This method is declared public because it's a hook callback. Calling it directly is not recommended.
	 */
	public function maybeCheckForUpdates(){
		if ( empty($this->checkPeriod) ){
			return;
		}

		$state = $this->updateChecker->getUpdateState();
		$shouldCheck =
			empty($state) ||
			!isset($state->lastCheck) ||
			( (time() - $state->lastCheck) >= $this->getEffectiveCheckPeriod() );

		//Let plugin authors substitute their own algorithm.
		$shouldCheck = apply_filters(
			'puc_check_now-' . $this->updateChecker->slug,
			$shouldCheck,
			(!empty($state) && isset($state->lastCheck)) ? $state->lastCheck : 0,
			$this->checkPeriod
		);

		if ( $shouldCheck ) {
			$this->updateChecker->checkForUpdates();
		}
	}

	/**
	 * Calculate the actual check period based on the current status and environment.
	 *
	 * @return int Check period in seconds.
	 */
	protected function getEffectiveCheckPeriod() {
		$currentFilter = current_filter();
		if ( in_array($currentFilter, array('load-update-core.php', 'upgrader_process_complete')) ) {
			//Check more often when the user visits "Dashboard -> Updates" or does a bulk update.
			$period = 60;
		} else if ( in_array($currentFilter, array('load-plugins.php', 'load-update.php')) ) {
			//Also check more often on the "Plugins" page and /wp-admin/update.php.
			$period = 3600;
		} else if ( $this->throttleRedundantChecks && ($this->updateChecker->getUpdate() !== null) ) {
			//Check less frequently if it's already known that an update is available.
			$period = $this->throttledCheckPeriod * 3600;
		} else if ( defined('DOING_CRON') && constant('DOING_CRON') ) {
			//WordPress cron schedules are not exact, so lets do an update check even
			//if slightly less than $checkPeriod hours have elapsed since the last check.
			$cronFuzziness = 20 * 60;
			$period = $this->checkPeriod * 3600 - $cronFuzziness;
		} else {
			$period = $this->checkPeriod * 3600;
		}

		return $period;
	}

	/**
	 * Add our custom schedule to the array of Cron schedules used by WP.
	 *
	 * @param array $schedules
	 * @return array
	 */
	public function _addCustomSchedule($schedules){
		if ( $this->checkPeriod && ($this->checkPeriod > 0) ){
			$scheduleName = 'every' . $this->checkPeriod . 'hours';
			$schedules[$scheduleName] = array(
				'interval' => $this->checkPeriod * 3600,
				'display' => sprintf('Every %d hours', $this->checkPeriod),
			);
		}
		return $schedules;
	}

	/**
	 * Remove the scheduled cron event that the library uses to check for updates.
	 *
	 * @return void
	 */
	public function _removeUpdaterCron(){
		wp_clear_scheduled_hook($this->cronHook);
	}

	/**
	 * Get the name of the update checker's WP-cron hook. Mostly useful for debugging.
	 *
	 * @return string
	 */
	public function getCronHookName() {
		return $this->cronHook;
	}
}

endif;


if ( !class_exists('SpeedyCache_PucUpgraderStatus_3_2', false) ):

/**
 * A utility class that helps figure out which plugin WordPress is upgrading.
 *
 * It may seem strange to have an separate class just for that, but the task is surprisingly complicated.
 * Core classes like Plugin_Upgrader don't expose the plugin file name during an in-progress update (AFAICT).
 * This class uses a few workarounds and heuristics to get the file name.
 */
#[\AllowDynamicProperties]
class SpeedyCache_PucUpgraderStatus_3_2 {
	private $upgradedPluginFile = null; //The plugin that is currently being upgraded by WordPress.

	public function __construct() {
		//Keep track of which plugin WordPress is currently upgrading.
		add_filter('upgrader_pre_install', array($this, 'setUpgradedPlugin'), 10, 2);
		add_filter('upgrader_package_options', array($this, 'setUpgradedPluginFromOptions'), 10, 1);
		add_filter('upgrader_post_install', array($this, 'clearUpgradedPlugin'), 10, 1);
		add_action('upgrader_process_complete', array($this, 'clearUpgradedPlugin'), 10, 1);
	}

	/**
	 * Is there and update being installed RIGHT NOW, for a specific plugin?
	 *
	 * Caution: This method is unreliable. WordPress doesn't make it easy to figure out what it is upgrading,
	 * and upgrader implementations are liable to change without notice.
	 *
	 * @param string $pluginFile The plugin to check.
	 * @param WP_Upgrader|null $upgrader The upgrader that's performing the current update.
	 * @return bool True if the plugin identified by $pluginFile is being upgraded.
	 */
	public function isPluginBeingUpgraded($pluginFile, $upgrader = null) {
		if ( isset($upgrader) ) {
			$upgradedPluginFile = $this->getPluginBeingUpgradedBy($upgrader);
			if ( !empty($upgradedPluginFile) ) {
				$this->upgradedPluginFile = $upgradedPluginFile;
			}
		}
		return ( !empty($this->upgradedPluginFile) && ($this->upgradedPluginFile === $pluginFile) );
	}

	/**
	 * Get the file name of the plugin that's currently being upgraded.
	 *
	 * @param Plugin_Upgrader|WP_Upgrader $upgrader
	 * @return string|null
	 */
	private function getPluginBeingUpgradedBy($upgrader) {
		if ( !isset($upgrader, $upgrader->skin) ) {
			return null;
		}

		//Figure out which plugin is being upgraded.
		$pluginFile = null;
		$skin = $upgrader->skin;
		if ( $skin instanceof Plugin_Upgrader_Skin ) {
			if ( isset($skin->plugin) && is_string($skin->plugin) && ($skin->plugin !== '') ) {
				$pluginFile = $skin->plugin;
			}
		} elseif ( isset($skin->plugin_info) && is_array($skin->plugin_info) ) {
			//This case is tricky because Bulk_Plugin_Upgrader_Skin (etc) doesn't actually store the plugin
			//filename anywhere. Instead, it has the plugin headers in $plugin_info. So the best we can
			//do is compare those headers to the headers of installed plugins.
			$pluginFile = $this->identifyPluginByHeaders($skin->plugin_info);
		}

		return $pluginFile;
	}

	/**
	 * Identify an installed plugin based on its headers.
	 *
	 * @param array $searchHeaders The plugin file header to look for.
	 * @return string|null Plugin basename ("foo/bar.php"), or NULL if we can't identify the plugin.
	 */
	private function identifyPluginByHeaders($searchHeaders) {
		if ( !function_exists('get_plugins') ){
			/** @noinspection PhpIncludeInspection */
			require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
		}

		$installedPlugins = get_plugins();
		$matches = array();
		foreach($installedPlugins as $pluginBasename => $headers) {
			$diff1 = array_diff_assoc($headers, $searchHeaders);
			$diff2 = array_diff_assoc($searchHeaders, $headers);
			if ( empty($diff1) && empty($diff2) ) {
				$matches[] = $pluginBasename;
			}
		}

		//It's possible (though very unlikely) that there could be two plugins with identical
		//headers. In that case, we can't unambiguously identify the plugin that's being upgraded.
		if ( count($matches) !== 1 ) {
			return null;
		}

		return reset($matches);
	}

	/**
	 * @access private
	 *
	 * @param mixed $input
	 * @param array $hookExtra
	 * @return mixed Returns $input unaltered.
	 */
	public function setUpgradedPlugin($input, $hookExtra) {
		if (!empty($hookExtra['plugin']) && is_string($hookExtra['plugin'])) {
			$this->upgradedPluginFile = $hookExtra['plugin'];
		} else {
			$this->upgradedPluginFile = null;
		}
		return $input;
	}

	/**
	 * @access private
	 *
	 * @param array $options
	 * @return array
	 */
	public function setUpgradedPluginFromOptions($options) {
		if (isset($options['hook_extra']['plugin']) && is_string($options['hook_extra']['plugin'])) {
			$this->upgradedPluginFile = $options['hook_extra']['plugin'];
		} else {
			$this->upgradedPluginFile = null;
		}
		return $options;
	}

	/**
	 * @access private
	 *
	 * @param mixed $input
	 * @return mixed Returns $input unaltered.
	 */
	public function clearUpgradedPlugin($input = null) {
		$this->upgradedPluginFile = null;
		return $input;
	}
}

endif;


if ( !class_exists('SpeedyCache_PucFactory', false) ):

/**
 * A factory that builds instances of other classes from this library.
 *
 * When multiple versions of the same class have been loaded (e.g. SpeedyCacheUpdateChecker 1.2
 * and 1.3), this factory will always use the latest available version. Register class
 * versions by calling {@link SpeedyCache_PucFactory::addVersion()}.
 *
 * At the moment it can only build instances of the SpeedyCacheUpdateChecker class. Other classes
 * are intended mainly for internal use and refer directly to specific implementations. If you
 * want to instantiate one of them anyway, you can use {@link SpeedyCache_PucFactory::getLatestClassVersion()}
 * to get the class name and then create it with <code>new $class(...)</code>.
 */
#[\AllowDynamicProperties]
class SpeedyCache_PucFactory {
	protected static $classVersions = array();
	protected static $sorted = false;

	/**
	 * Create a new instance of SpeedyCacheUpdateChecker.
	 *
	 * @see SpeedyCacheUpdateChecker::__construct()
	 *
	 * @param $metadataUrl
	 * @param $pluginFile
	 * @param string $slug
	 * @param int $checkPeriod
	 * @param string $optionName
	 * @param string $muPluginFile
	 * @return SpeedyCacheUpdateChecker_3_2
	 */
	public static function buildUpdateChecker($metadataUrl, $pluginFile, $slug = '', $checkPeriod = 12, $optionName = '', $muPluginFile = '') {
		$class = self::getLatestClassVersion('SpeedyCacheUpdateChecker');
		return new $class($metadataUrl, $pluginFile, $slug, $checkPeriod, $optionName, $muPluginFile);
	}

	/**
	 * Get the specific class name for the latest available version of a class.
	 *
	 * @param string $class
	 * @return string|null
	 */
	public static function getLatestClassVersion($class) {
		if ( !self::$sorted ) {
			self::sortVersions();
		}

		if ( isset(self::$classVersions[$class]) ) {
			return reset(self::$classVersions[$class]);
		} else {
			return null;
		}
	}

	/**
	 * Sort available class versions in descending order (i.e. newest first).
	 */
	protected static function sortVersions() {
		foreach ( self::$classVersions as $class => $versions ) {
			uksort($versions, array(__CLASS__, 'compareVersions'));
			self::$classVersions[$class] = $versions;
		}
		self::$sorted = true;
	}

	protected static function compareVersions($a, $b) {
		return -version_compare($a, $b);
	}

	/**
	 * Register a version of a class.
	 *
	 * @access private This method is only for internal use by the library.
	 *
	 * @param string $generalClass Class name without version numbers, e.g. 'SpeedyCacheUpdateChecker'.
	 * @param string $versionedClass Actual class name, e.g. 'SpeedyCacheUpdateChecker_1_2'.
	 * @param string $version Version number, e.g. '1.2'.
	 */
	public static function addVersion($generalClass, $versionedClass, $version) {
		if ( !isset(self::$classVersions[$generalClass]) ) {
			self::$classVersions[$generalClass] = array();
		}
		self::$classVersions[$generalClass][$version] = $versionedClass;
		self::$sorted = false;
	}
}

endif;

//Register classes defined in this file with the factory.
SpeedyCache_PucFactory::addVersion('SpeedyCacheUpdateChecker', 'SpeedyCacheUpdateChecker_3_2', '3.2');
SpeedyCache_PucFactory::addVersion('SpeedyCacheUpdate', 'SpeedyCacheUpdate_3_2', '3.2');
SpeedyCache_PucFactory::addVersion('SpeedyCacheInfo', 'SpeedyCacheInfo_3_2', '3.2');
SpeedyCache_PucFactory::addVersion('SpeedyCache_PucGitHubChecker', 'SpeedyCache_PucGitHubChecker_3_2', '3.2');
lazyload.php000064400000035312151526435100007102 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class LazyLoad{
	static function init(){
		global $speedycache;
		
		$speedycache->lazy_load = array();
		$speedycache->lazy_load['exclude'] = array();
		$speedycache->lazy_load['host'] = '';
		$speedycache->lazy_load['placeholder'] = '';
		$url = parse_url(site_url());
		$speedycache->lazy_load['host'] = $url['host'];

		if(!empty($speedycache->options['lazy_load_keywords']) && $speedycache->options['lazy_load_keywords']){
			if(is_string($speedycache->options['lazy_load_keywords'])){
				$speedycache->lazy_load['exclude'] = explode(',', $speedycache->options['lazy_load_keywords']);
			} else {
				$speedycache->lazy_load['exclude'] = $speedycache->options['lazy_load_keywords'];
			}
		}
		
		self::set_placeholder();
	}

	static function set_placeholder(){
		global $speedycache;
		
		if(!empty($speedycache->options['lazy_load_placeholder']) && $speedycache->options['lazy_load_placeholder']){
			
			if($speedycache->options['lazy_load_placeholder'] === 'default'){
				$speedycache->lazy_load['placeholder'] = SPEEDYCACHE_PRO_URL . '/assets/images/image-palceholder.png';
			} else if($speedycache->options['lazy_load_placeholder'] === 'base64'){
				$speedycache->lazy_load['placeholder'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
			} else if($speedycache->options['lazy_load_placeholder'] === 'custom' && !empty($speedycache->options['lazy_load_placeholder_custom_url'])){
				$speedycache->lazy_load['placeholder'] = $speedycache->options['lazy_load_placeholder_custom_url'];
			}
			
			return;
		} 
		
		$speedycache->lazy_load['placeholder'] = SPEEDYCACHE_PRO_URL . '/assets/images/image-palceholder.png';
		return;
	}

	static function instagram($tag){
		$src = false;

		if(preg_match("/src\s*\=\s*[\"\']([^\"\']+sb-instagram\.min\.js)/", $tag, $out)){
			$src = $out[1];
		}

		if(empty($src)){
			return $tag;
		}

		$tmp_script = '<script type="text/javascript">'.
		"window.addEventListener('scroll',function(){".
		"(function(d,s){".
		"if(document.querySelectorAll("."\"script[src='\""." + s + "."\"']\"".").length > 0){return;}".
		"var t = d.createElement('script');".
		't.setAttribute("src", s);'.
		"d.body.appendChild(t);".
		'})(document, "'.$src.'");'.
		"});".
		"</script>\n";

		return $tmp_script;
	}

	static function mark_images($content){
		global $speedycache;

		if(speedycache_is_mobile()){
			return $content;
		}

		preg_match_all('/<img[^\>]+>/i', $content, $matches);

		if(count($matches[0]) <= 0){
			return $content;
		}

		foreach($matches[0] as $img){
			if(self::is_thumbnail($img) || self::is_third_party($img) || !self::is_full($img)){
				continue;
			}

			$tmp_img = $img;

			if(strpos($img, 'decoding') === FALSE){
				$tmp_img = preg_replace("/<img\s/", '<img decoding="async" ', $img);
			}

			$tmp_img = preg_replace("/<img\s/", '<img speedycache-lazyload-disable="true" ', $tmp_img);

			$content = str_replace($img, $tmp_img, $content);
		}

		return $content;
	}

	static function mark_attachment_page_images($attr, $attachment){

		if(speedycache_is_mobile()){
			return $attr;
		}

		if(isset($attr['src'])){
			if(self::is_thumbnail($attr['src'])){
				return $attr;
			}

			if(self::is_third_party($attr['src'])){
				return $attr;
			}

			if(!self::is_full('<img src="' . $attr['src'] . '" class="' . $attr['class'] . '">')){
				return $attr;
			}
		}

		if(empty($attachment)){
			return $attr;
		}

		$attr['speedycache-lazyload-disable'] = 'true';

		return $attr;
	}

	static function is_thumbnail($src){
		
		$resolution_pregs = array(
			'/\-[12]\d{0,2}x[12]\d{0,2}\.(jpg|jpeg|png)/i', // < 299x299
			'/\-[12]\d{0,2}x\d{0,2}\.(jpg|jpeg|png)/i', // < 299x99
			'/\-\d{0,2}x[12]\d{0,2}\.(jpg|jpeg|png)/i', // < 99x299
			'/\-\d{0,2}x\d{0,2}\.(jpg|jpeg|png)/i' // < 99x99
		);
		
		foreach($resolution_pregs as $resolution_preg){
			if(preg_match($resolution_preg, $src)){
				return true;
			}
		}

		return false;
	}

	static function is_third_party($src){
		global $speedycache;
		
		if(preg_match('/' . preg_quote($speedycache->lazy_load['host'], '/') . '/i', $src)){
			return false;
		}

		return true;
	}

	static function is_full($img){
		
		// to check homepage. sometimes is_home() does not work
		if(isset($_SERVER['REQUEST_URI']) && strlen($_SERVER['REQUEST_URI']) < 2){
			return false;
		}

		if(is_home() || is_archive()){
			return false;
		}

		if(preg_match("/-\d+x\d+\.(jpg|jpeg|png)/i", $img)){
			if(preg_match("/\sclass\=[\"\'][^\"\']*size-medium[^\"\']*[\"\']/", $img)){
				return false;
			}
		}

		return true;
	}

	static function is_exclude($source){
		global $speedycache;
		
		/*
			to disable lazy load for rav-slider images
			<img data-bgposition="center center" data-bgparallax="8" data-bgfit="cover" data-bgrepeat="no-repeat"class="rev-slidebg" data-no-retina>
			<img width="1920" height="600" data-parallax="8" class="rev-slidebg" data-no-retina>
		*/
		if(preg_match('/class\="rev-slidebg"/i', $source) && preg_match("/data-(bg)*parallax\=/i", $source)){
			return true;
		}

		/*
			to exclude img tag which exists in json
			var xxx = {"content":"<a href=\"https:\/\/www.abc.com\"><img src='https:\/\/www.abc.com\/img.gif' \/><\/a>"}
		*/
		if(preg_match("/\\\\\//", $source)){
			return true;
		}

		/*
			<img src="my-image.jpg" data-no-lazy="1" alt="" width="100" width="100" />
			<img src="my-image.jpg" data-skip-lazy="1" alt="" width="100" width="100" />
		*/
		if(preg_match("/data-(no|skip)-lazy\s*\=\s*[\"\']\s*1\s*[\"\']/i", $source)){
			return true;
		}

		//Slider Revolution
		//<img src="dummy.png" data-lazyload="transparent.png" data-bgposition="center center" data-bgfit="cover" data-bgrepeat="no-repeat" data-bgparallax="off" class="rev-slidebg" data-no-retina>
		if(preg_match("/\sdata-lazyload\=[\"\']/i", $source)){
			return true;
		}

		//<img src="dummy.png" data-lazy-src="transparent.png">
		//<img src="dummy.png" data-gg-lazy-src="transparent.png">
		if(preg_match("/\sdata-([a-z-]*)lazy-src\=[\"\']/i", $source)){
			return true;
		}

		//<div style="background-image:url(&#039;https://www.g.com/site-data/plugins/bold-page-builder/img/image-palceholder.png&#039;);background-position:top;background-size:cover;" data-background_image_src="https://www.g.com/site-data/1.jpg">
		if(preg_match("/\sdata-background_image_src\=[\"\']/i", $source)){
			return true;
		}

		/*
		Smash Balloon Social Photo Feed
		<img src="https://site.com/site-data/plugins/instagram-feed/img/placeholder.png"
		*/
		if(preg_match('/instagram-feed\/img\/placeholder\.png/i', $source)){
			return true;
		}

		// don't to the replacement if the image is a data-uri
		if(preg_match("/src\=[\'\"]data\:image/i", $source)){
			return true;
		}


		foreach((array)$speedycache->lazy_load['exclude'] as $key => $value){
			if(preg_match('/' . preg_quote($value, '/') . '/i', $source)){
				return true;
			}
		}

		return false;
	}

	static function video($data, $inline_scripts){
		global $speedycache;
		
		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		$video_list = array();
		$video_start_index = false;

		for ($i = 0; $i < strlen($data); $i++){
			if(isset($data[$i - 5])){
				if(substr($data, $i - 5, 6) == '<video'){
					$video_start_index = $i - 5;
				}
			}

			if(isset($data[$i - 7])){
				if($video_start_index){
					if(substr($data, $i - 7, 8) == '</video>'){
						array_push($video_list, array('start' => $video_start_index, 'end' => $i));
						$video_start_index = false;
					}
				}
			}
		}

		if(!empty($video_list)){
			foreach(array_reverse($video_list) as $key => $value){
				$video_html = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));

				if(self::is_exclude($video_html)){
					continue;
				}

				$video_html = '<noscript data-type="speedycache">' . $video_html . '</noscript>';

				$data = substr_replace($data, $video_html, $value['start'], ($value['end'] - $value['start'] + 1));
			}
		}

		return $data;
	}

	static function background($content, $inline_scripts){
		global $speedycache;

		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		preg_match_all('/<(div|span|a|section|li)\s[^\>]*style\s*\=\s*[\"\'][^\"\']*(background\-image\s*\:\s*url\s*\(([^\)\(]+)\)\;?)[^\"\']*[\"\'][^\>]*>/i', $content, $matches, PREG_SET_ORDER);

		if(count($matches) > 0){
			/*
				[0] = full
				[1] = tag
				[2] = backgound image
				[3] = url
			*/
			foreach($matches as $key => $div){
				// don't to the replacement if the image appear in js
				if(preg_match("/" . preg_quote($div[0], '/') . '/i', $inline_scripts)){
					continue;
				}

				if(self::is_exclude($div[0])){
					continue;
				}

				$tmp = $div[0];
				//to remove backgound attribute
				$tmp = str_replace($div[2], '', $tmp);
				//to add lazy load attribute
				$div[3] = preg_replace("/[\"\']/", '', $div[3]);
				$tmp = preg_replace("/<([a-z]{1,4})\s/i", "<$1 data-speedycache-original-src='" . $div[3] . "' ", $tmp);

				$content = str_replace($div[0], $tmp, $content);
			}
		}

		return $content;
	}

	static function images($content, $inline_scripts){
		global $speedycache;

		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		$offset = 2;

		preg_match_all('/<img[^\>]+>/i', $content, $matches);
		$count = 0;
		if(count($matches[0]) > 0){
			foreach($matches[0] as $key => $img){
				$count++;
				$tmp_img = false;
				
				if(preg_match("/onload=[\"\']/i", $img)){
					continue;
				}

				if(preg_match("/src\s*\=\s*[\'\"]\s*[\'\"]/i", $img)){
					continue;
				}
				
				// Excluding images from lazy loading and adding fetchpriority to high,
				// as we need to load that image faster if we are not lazy loading them
				if(!empty($speedycache->options['exclude_above_fold']) && is_numeric($speedycache->options['exclude_above_fold'])){
					if($count < $speedycache->options['exclude_above_fold']){
						$tmp_img = $img;
						$img = preg_replace('/fetchpriority=["\'].*["\']/Us', '', $img);
						$img = preg_replace('/loading=["\'].*["\']/Us', '', $img);
						$img = preg_replace('/decoding=["\'].*["\']/Us', '', $img);
						
						$img = str_replace('<img', '<img fetchpriority="high" loading="eager" decoding="async" ', $img);
						$content = str_replace($tmp_img, $img, $content);

						continue;
					}
				}

				$should_continue = self::replace_img($inline_scripts, $img, $content);
				
				if(!empty($should_continue)){
					continue;
				}

				$tmp_img = preg_replace("/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/", " ", $img);
				$content = str_replace($img, $tmp_img, $content);
			}
		}

		return $content;
	}

	static function inject_data_src($img){
		global $speedycache;
		
		if(!preg_match("/\ssrc\s*\=[\"\'][^\"\']+[\"\']/i", $img)){
			return $img;
		}
		
		if(preg_match("/mc\.yandex\.ru\/watch/i", $img)){
			return $img;
		}

		$tmp_img = $img;
		$tmp_img = preg_replace('/\ssrc\s*\=/i', ' data-speedycache-original-src=', $tmp_img);
		$tmp_img = preg_replace('/\ssrcset\s*\=/i', ' data-speedycache-original-srcset=', $tmp_img);
		$tmp_img = preg_replace('/\ssizes\s*\=/i', ' data-speedycache-original-sizes=', $tmp_img);
		$tmp_img = preg_replace('/<img\s/i', '<img onload="speedycachell.r(this,true);" src="' . $speedycache->lazy_load['placeholder'] . "$2\" ", $tmp_img);

		// to add alt attribute for seo
		$tmp_img = preg_replace('/\salt\s*\=\s*[\"|\']\s*[\"|\']/', ' alt="blank"', $tmp_img);
		if(!preg_match('/\salt\s*\=\s*/i', $tmp_img)){
			$tmp_img = preg_replace('/<img\s+/i', '<img alt="blank" ', $tmp_img);
		}

		return $tmp_img;
	}

	static function replace_img($inline_scripts, $img, &$content){
		
		$tmp_img = false;
		
		// Don't do the replacement if the image appear in js
		if(preg_match('/' . preg_quote($img, '/') . '/i', $inline_scripts)){
			return false;
		}

		// Don't do the replacement if quote of src does not exist
		if(!preg_match("/\ssrc\s*\=[\"\']/i", $img) && preg_match("/<img/i", $img)){
			return true;
		}

		if(self::is_exclude($img)){
			$tmp_img = preg_replace('/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/', ' ', $img);
		} else if(preg_match('/speedycache-lazyload-disable/', $img)){
			$tmp_img = preg_replace('/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/', ' ', $img);
		} else {
			$tmp_img = self::inject_data_src($img);
		}
		
		if($tmp_img){
			$content = str_replace($img, $tmp_img, $content);
		}
		
		return true;
	}

	static function iframe($content, $inline_scripts){
		
		preg_match_all('/<iframe[^\>]+>/i', $content, $matches);

		if(count($matches[0]) > 0){
			foreach($matches[0] as $iframe){
				if(self::is_exclude($iframe)){
					continue;
				}

				self::iframe_replace($inline_scripts, $iframe, $content);
			}
		}

		return $content;
	}

	static function iframe_replace($inline_scripts, $iframe, &$content){
		// don't to the replacement if the frame appear in js
		if(preg_match('/' . preg_quote($iframe, "/") . '/i', $inline_scripts)){
			return;
		}

		if(preg_match("/onload=[\"\']/i", $iframe)){
			return;
		}

		if(preg_match("/(youtube|youtube-nocookie)\.com\/embed/i", $iframe) && !preg_match("/videoseries\?list/i", $iframe)){
			// to exclude /videoseries?list= because of problem with getting thumbnail
			$tmp_iframe = preg_replace("/\ssrc\=[\"\'](https?\:)?\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/([^\"\']+)[\"\']/i", " onload=\"speedycachell.r(this,true);\" data-speedycache-original-src=\"" . SPEEDYCACHE_WP_CONTENT_URL . "/plugins/".SPEEDYCACHE_PRO_BASE_NAME."/main/youtube.html#$4\"", $iframe);
		} else {
			$tmp_iframe = preg_replace("/\ssrc\=/i", " onload=\"speedycachell.r(this,true);\" data-speedycache-original-src=", $iframe);
		}

		$content = str_replace($iframe, $tmp_iframe, $content);

	}

	static function get_js_source(){
		
		$js = "\n<script data-speedycache-render=\"false\">" . file_get_contents(SPEEDYCACHE_PRO_DIR . '/assets/js/lazy-load.js') . "</script>\n";

		/**
		  * Structure of this array is
		  * searchable => replacer
		*/
		$js_replaces = array(
			'/\/\*[^\n]+\*\//' =>  '', //to remove comments
			'/var\sself/' => 'var s',
			'/self\./' => 's.',
			'/speedycache_lazy_load/' => 'speedycachell',
			'/(\.?)init(\:?)/' => '$1i$2',
			'/(\.?)load_images(\:?)/' => '$1li$2',
			'/\s*(\+|\=|\:|\;|\{|\}|\,)\s*/' => '$1',
			'/originalsrcset/' => 'ot',
			'/originalsrc/' => 'oc',
			'/load_sources/' => 'ls',
			'/set_source/' => 'ss',
			'/sources/' => 's',
			'/winH/' => 'w',
			'/number/' => 'n',
			'/elemRect/' => 'er',
			'/parentRect/' => 'pr',
			'/parentOfE/' => 'p',
			'/top(\=|\+)/' => 't$1'
		);
		
		foreach($js_replaces as $search => $replace){
			$js = preg_replace($search, $replace, $js);
		}

		return $js;
	}

}

enhanced.php000064400000134337151526435100007037 0ustar00<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class Enhanced{

	static function init(){
		global $speedycache;
		
		$speedycache->enhanced = array();
		$speedycache->enhanced['html'] = '';
		$speedycache->enhanced['head_html'] = '';
		$speedycache->enhanced['body_html'] = '';
		$speedycache->enhanced['inline_scripts'] = '';
		$speedycache->enhanced['cache_speedycache_minified'] = '';
		$speedycache->enhanced['cache_speedycache_minified'] = 'cache/speedycache/'.SPEEDYCACHE_SERVER_HOST. '/assets';
	}
	
	// Removes white space after </html> & \r & any white space 
	static function remove_trailing_html_space($content){
		global $speedycache;
		
		$content = preg_replace("/<\/html>\s+/", '</html>', $content);
		$content = str_replace("\r", '', $content);
		return preg_replace("/^\s+/m", '', ((string) $content));
	}

	static function remove_head_comments(){
		global $speedycache;
		
		$data = $speedycache->enhanced['head_html'];
		$comment_list = array();
		$comment_start_index = false;

		for($i = 0; $i < strlen( $data ); $i++){
			if(isset($data[$i-3])){
				if($data[$i-3].$data[$i-2].$data[$i-1].$data[$i] == '<!--'){
					if(!preg_match("/if\s+|endif\s*\]/", substr($data, $i, 17))){
						$comment_start_index = $i-3;
					}
				}
			}

			if(isset($data[$i-2])){
				if($comment_start_index){
					if($data[$i-2].$data[$i-1].$data[$i] == '-->'){
						array_push($comment_list, array('start' => $comment_start_index, 'end' => $i));
						$comment_start_index = false;
					}
				}
			}
		}

		if(!empty($comment_list)){
			foreach(array_reverse($comment_list) as $key => $value){
				$data = substr_replace($data, '', $value['start'], ($value['end'] - $value['start'] + 1));
			}

			$speedycache->enhanced['html'] = str_replace($speedycache->enhanced['head_html'], $data, $speedycache->enhanced['html']);
		}

		return $speedycache->enhanced['html'];
	}

	static function eliminate_newline($start_string, $end_string, $tmp_html){
		$data = $tmp_html;

		$list = array();
		$start_index = false;
		$end_index = false;

		for($i = 0; $i < strlen( $data ); $i++){
			if(substr($data, $i, strlen($start_string)) == $start_string){
				if(!$end_index){
					$start_index = $i;
				}
			}

			if($start_index && $i > $start_index){
				if(substr($data, $i, strlen($end_string)) == $end_string){
					$end_index = $i + strlen($end_string) - 1;
					$text = substr($data, $start_index, ($end_index - $start_index + 1));
					
					array_push($list, array('start' => $start_index, 'end' => $end_index, 'text' => $text));

					$start_index = false;
					$end_index = false;
				}
			}
		}

		if(isset($list[0])){
			$list = array_reverse($list);

			foreach($list as $key => $value){
				if(preg_match("/(<script|<style|<textarea)/i", $value['text'])){
					continue;
				}

				//var $bodybg=$('<div id="ncf-body-bg"/>').prependTo($body);
				if(preg_match("/\)\.prependTo\(/i", $value['text'])){
					continue;
				}

				//<div class="wp_syntax" style="position:relative;">
				if(preg_match("/<div\s+class\=\"wp\_syntax\"[^\>]*>/i", $value['text'])){
					continue;
				}

				$value['text'] = preg_replace("/\s+/", " ", ((string)$value['text']));

				$tmp_html = substr_replace($tmp_html, $value['text'], $value['start'], ($value['end'] - $value['start'] + 1));
			}
		}

		return $tmp_html;
	}

	static function minify_inline_css($data){
		global $speedycache;
		
		$style_list = array();
		$style_start_index = false;

		for($i = 0; $i < strlen( $data ); $i++){
			if(isset($data[$i-5])){
				if(substr($data, $i - 5, 6) == '<style'){
					$style_start_index = $i - 5;
				}
			}

			if(isset($data[$i-7])){
				if($style_start_index){
					if(substr($data, $i - 7, 8) == '</style>'){
						array_push($style_list, array('start' => $style_start_index, 'end' => $i));
						$style_start_index = false;
					}
				}
			}
		}

		if(!empty($style_list)){
			foreach(array_reverse($style_list) as $key => $value){
				// document.write('<style type="text/css">div{}</style')
				$prev_20_chars = substr($data, $value['start'] - 20, 20);
				
				if(strpos($prev_20_chars, 'document.write') !== false){
					continue;
				}

				$inline_style = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));
				
				if(strlen($inline_style) > 15000){
					$part_of_inline_style = substr($inline_style, 0, 15000);
				}else{
					$part_of_inline_style = $inline_style;
				}

				if(preg_match('/'.preg_quote($part_of_inline_style, '/').'/i', $speedycache->enhanced['inline_scripts'])){
					continue;
				}

				if(preg_match("/<style\s+(amp-boilerplate|amp-custom)>/", $inline_style)){
					continue;	
				}

				$inline_style = \SpeedyCache\Enhanced::minify_css($inline_style);

				$inline_style = preg_replace("/\/\*(.*?)\*\//s", "\n", $inline_style); //replaces comments with \n
				$inline_style = preg_replace("/(<style[^\>]*>)\s+/i", "$1", $inline_style); //removes white space after <style> tag
				$inline_style = preg_replace("/\s+(<\/style[^\>]*>)/i", "$1", $inline_style); //removes white space before </style> tag

				$inline_style = str_replace(' type="text/css"', '', $inline_style);
				$inline_style = str_replace(' type="text/css"', '', $inline_style);

				$data = substr_replace($data, $inline_style, $value['start'], ($value['end'] - $value['start'] + 1));
			}
		}

		return $data;
	}

	static function remove_html_comments($data){
		$comment_list = array();
		$comment_start_index = false;

		for($i = 0; $i < strlen($data); $i++){
			if(isset($data[$i-3])){
				if($data[$i-3].$data[$i-2].$data[$i-1].$data[$i] == "<!--"){
					if(!preg_match("/if\s+|endif\s*\]/", substr($data, $i, 17))){
						$comment_start_index = $i-3;
					}
				}
			}

			if(isset($data[$i-2])){
				if($comment_start_index){
					if($data[$i-2].$data[$i-1].$data[$i] == '-->'){
						array_push($comment_list, array('start' => $comment_start_index, 'end' => $i));
						$comment_start_index = false;
					}
				}
			}
		}

		if(!empty($comment_list)){
			foreach(array_reverse($comment_list) as $key => $value){
				if(($value['end'] - $value['start']) > 4){
					$comment_html = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));

					if(preg_match("/google\_ad\_slot/i", $comment_html)){
					}else{
						$data = substr_replace($data, '', $value['start'], ($value['end'] - $value['start'] + 1));
					}
				}
			}
		}

		return $data;
	}

	static function minify_html(&$content){
		global $speedycache;
		
		if(defined('SPEEDYCACHE_VERSION') && version_compare(SPEEDYCACHE_VERSION, '1.2.0', '<')){
			return $speedycache->enhanced['html'];
		}
		
		$tmp_html = $content;

		$tmp_html = self::remove_trailing_html_space($tmp_html);
		$tmp_html = self::eliminate_newline('<div', '</div>', $tmp_html);
		$tmp_html = self::eliminate_newline('<li', '</li>', $tmp_html);

		$tmp_html = self::minify_inline_js($tmp_html);
		$tmp_html = self::minify_inline_css($tmp_html);

		$tmp_html = self::remove_html_comments($tmp_html);

		$tag_list = 'p|div|span|img|nav|ul|li|header|a|b|i|article|section|footer|style|script|link|meta|body';

		$tmp_html = preg_replace_callback("/\<(".$tag_list.")\s+[^\>\<]+\>/i", '\SpeedyCache\Enhanced::remove_spaces_in_tag', $tmp_html);
		$tmp_html = preg_replace('/\h+<\//', '</', $tmp_html);
		
		// BECAUSE of JsemÂ<span class="label">
		// - need to remove spaces between >  <
		// - need to remove spaces between <span>  Assdfdf </span>
		// $tmp_html = preg_replace("/\h*\<(".$tag_list.")\s+([^\>]+)>\h*/i", "<$1 $2>", $tmp_html);
		// $tmp_html = preg_replace("/\h*\<\/(".$tag_list.")>\h*/i", "</$1>", $tmp_html);
		$tmp_html = preg_replace("/\s*<\/div>\s*/is", "</div>", $tmp_html);
		
		$content = $tmp_html;
	}

	static function search_in_inline_scripts($content){
		global $speedycache;
		
		if(strpos($speedycache->enhanced['inline_scripts'], $content) === false){
			return false;
		}
		
		return true;
	}

	static function remove_spaces_in_tag($matches){
		if(self::search_in_inline_scripts($matches[0])){
			return $matches[0];
		}
		
		/**
		  * Structure of this array is
		  * searchable => replacer
		*/	
		$pregs_replaces = array(
			'/([\"\'])\s+\/>/' => '$1/>', //  <img id="1"  />
			'/\s+/' => ' ', // <div      id="1">
			'/\s+([\"\'])/' => '$1', // <div id="1  ">
			'/([a-z])\=([\"\'])\s+/' => '$1=$2', // <div id="  1"> <img src="data:image/gif;base64,R0lAICRAEAOw==" lazy="image.jpg" />
			'/\h*class\=\'\'\h*/' => ' ', // <ul class="">
			'/\h*class\=\"\"\h*/' => ' ', // <ul class=''>
		);
		
		foreach($pregs_replaces as $searchable => $replacer){
			$matches[0] = preg_replace($searchable, $replacer, $matches[0]);
		}

		// <div style="">
		if(!preg_match("/id\=\"ctf_/", $matches[0])){
			/* 
			to exclude for Custom Twitter Feeds Pro Personal
			<div class="ctf-item ctf-author-msdsmarine ctf-new ctf-hide-avatar ctf-retweet ctf-tc-checked" id="ctf_1323705595325800448" style="">
			*/
			$matches[0] = preg_replace("/\h*style\=[\"\'][\"\']\h*/", " ", $matches[0]);
		}

		// <div id="1"  >
		// <div  >
		$matches[0] = preg_replace("/\h+\>/", ">", $matches[0]);

		// <script src='//bqcmw.js' type="text/javascript"></script>
		//$matches[0] = self::remove_type_attribute_for_js($matches[0]);

		return $matches[0];
	}

	static function remove_type_attribute_for_js($script){
		if(preg_match("/src\s*\=\s*[\"\']/", $script)){
			$script = preg_replace("/\stype\s*\=\s*[\'\"][^\"\']+[\'\"]/", " ", $script);
			$script = preg_replace("/\s+/", " ", $script);
			$script = preg_replace("/([\'\"])\s>/", "$1>", $script);
		}

		return $script;
	}

	static function remove_single_line_comments($html){
		$html = preg_replace("/<!--((?:(?!-->).)+)-->/", '', $html);
		$html = preg_replace("/\/\*((?:(?!\*\/).)+)\*\//", '', $html);
		return $html;
	}

	/* CSS Part Start */
	static function minify_css($source){
		$data = $source;
		$curl_list = array();
		$curl_start_index = false;

		$curl_start_count = 0;
		$curl_end_count = 0;

		for($i = 0; $i < strlen( $data ); $i++){
			if($data[$i] == '{'){
				$curl_start_count++;
				if(!$curl_start_index){
					$curl_start_index = $i;
				}
			}

			if($data[$i] == '}'){
				// .icon-basic-printer:before{content:"}";}
				if(isset($data[$i+1]) && $data[$i+1] != "'" && $data[$i+1] != "'"){
					$curl_end_count++;
				}
			}

			if($curl_start_count && $curl_start_count == $curl_end_count){
				array_push($curl_list, array('start' => $curl_start_index - 3, 'end' => $i + 3));

				$curl_start_count = 0;
				$curl_end_count = 0;
				$curl_start_index = false;
			}
		}

		if(!empty($curl_list)){
			foreach(array_reverse($curl_list) as $key => $value){
				$new_data = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));

				if(!preg_match("/[^\{]+\{[^\{]+\{/", $new_data)){
					$new_data = preg_replace("/\s+/", " ", ((string) $new_data));
					$new_data = preg_replace("/\s+}/", "}", $new_data); //removes white space before "}"
					$new_data = preg_replace("/}\s+/", "} ", $new_data); //removes white space after "}"
					$new_data = preg_replace("/\s*(\{|\;|\:)\s*/", "$1", $new_data);

					$data = substr_replace($data, $new_data, $value['start'], ($value['end'] - $value['start'] + 1));

				}else{
					$first = strpos($new_data, '{');
					$last = strrpos($new_data, '}');
					$new_data_tmp = substr($new_data, $first+1, $last-$first-1);
					$new_data_tmp = \SpeedyCache\Enhanced::minify_css($new_data_tmp);

					$new_data = substr_replace($new_data, $new_data_tmp, $first+1, ($last-$first-1));

					$data = substr_replace($data, $new_data, $value['start'], ($value['end'] - $value['start'] + 1));
				}
			}

			$source = $data;
		}

		//@media (max-width: 767px){
		$source = preg_replace("/\@media\s*\(\s*(max-width|min-width)\s*\:\s*([^\(\)\{\}\s]+)\s*\)\s*\{/", "@media($1:$2){", $source);
		//@media (min-width: 768px) and (max-width: 1018px){
		$source = preg_replace("/\@media\s*\(\s*(max-width|min-width)\s*\:\s*([^\(\)\{\}\s]+)\s*\)\s*and\s*\(\s*(max-width|min-width)\s*\:\s*([^\(\)\{\}\s]+)\s*\)\s*\{/", "@media($1:$2) and ($3:$4){", $source);
		//@media screen and (max-width: 479px){
		$source = preg_replace("/\@media\s+screen\s+and\s*\(\s*(max-width|min-width)\s*\:\s*([^\(\)\{\}\s]+)\s*\)\s*\{/", "@media screen and ($1:$2){", $source);

		/*
		article,
		h2,
		div:first-child,
		.main{padding:0;}
		*/
		$source = preg_replace("/^([a-z0-9\_\.\-\:\>\s]+\,)\s+/im", "$1 ", $source);

		return $source;

		//$source = preg_replace_callback("/\s*\{((?:(?!content|\}).)+)\}\s*/", '\SpeedyCache\Enhanced::eliminate_newline_for_css'), $source);
		//return $source;
	}

	// Regex to replace new line after \n /\s*\;(?:\s*|\n)/
	//Replaces Space before and after { } ; :
	static function eliminate_newline_for_css($matches){
		$matches[0] = preg_replace("/\s+/", " ", ((string) $matches[0]));
		$matches[0] = preg_replace("/\s*{\s*/", "{", $matches[0]);
		$matches[0] = preg_replace("/\s*}\s*/", "}", $matches[0]);
		$matches[0] = preg_replace("/\s*\;\s*/", ";", $matches[0]);
		$matches[0] = preg_replace("/\s*\:\s*/", ":", $matches[0]);

		return $matches[0]."\n";
	}

	static function render_blocking($html, $render_blocking_css = false){
		\SpeedyCache\RenderBlocking::init($html);
		return \SpeedyCache\RenderBlocking::action($render_blocking_css);
	}

	static function google_fonts(){
		//for checking
	}

	static function lazy_load($content){
		global $speedycache;

		\SpeedyCache\LazyLoad::init();
		
		$funcs = array(
			'\SpeedyCache\LazyLoad::images',
			'\SpeedyCache\LazyLoad::iframe',
			'\SpeedyCache\LazyLoad::background',
			'\SpeedyCache\LazyLoad::video'
		);
		
		foreach($funcs as $fn){
			// if(!function_exists($fn)){
				// continue;
			// }

			$fn_res = call_user_func_array($fn, array($content, $speedycache->enhanced['inline_scripts']));
			
			if(empty($fn_res)){
				continue;
			}
			
			$content = $fn_res;
		
		}
		
		return $content;
	}

	/* CSS Part Start */

	/* Js Part Start */
	// TODO:: not used anywhere
	static function single_line_js($source){
		$source = preg_replace("/\n/", '', $source);

		return $source;
	}

	static function minify_js($source, $inline_js = false){
		//$source = preg_replace("/\n\/\/.*/", "", $source);
		//$source = preg_replace("/\/\*.*?\*\//s", "", $source);

		if(preg_match("/dynamicgoogletags\.update\(\)/i", $source)){
			$source = "<script>dynamicgoogletags.update();</script>";
			
			return $source;
		}

		// <script>
		//   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
		//   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
		//   m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
		//   })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

		//   ga('create', 'UA-9999-9', 'auto');
		//   ga('send', 'pageview');
		// </script>
		if(preg_match("/<script[^\>]*>\s*\(function\(i,s,o,g,r,a,m\)\{i\[\'GoogleAnalyticsObject\'\]/i", $source)){
			if(preg_match("/ga\(\'send\',\s*\'pageview\'\)\;\s*<\/script>/i", $source)){
				$source = preg_replace("/\s+/", " ", ((string) $source));
				$source = preg_replace("/\s*<(\/?)script([^\>]*)>\s*/", "<$1script$2>", $source);

				return $source;
			}
		}

		// sometimes the lines are ended with "\r" instead of "\n"
		$source = str_replace("\r", "\n", $source);

		$source = preg_replace("/^\s+/m", '', $source);

		if(empty($inline_js)){
			// // --></script> in html
			//$source = preg_replace("/\n\/\/[^\n]+/", "", $source); // to remove single line comments
			$source = preg_replace_callback("/\n\/\/[^\n]+/", '\SpeedyCache\Enhanced::remove_single_line_comments_from_js', $source);
		}

		if(!empty($inline_js)){
			if(preg_match("/var\sptsTables/i", $source) && preg_match("/var\sptsBuildConst/i", $source)){
			}
			//to remove only CDATA from inline js
			$source = preg_replace("/\/\*\s*\<\!\[CDATA\[\s*\*\//", "", $source);
			$source = preg_replace("/\/\*\s*\]\]\>\s*\*\//", "", $source);
		}

		//<script>//alert();</script>
		if(preg_match("/<script[^\>]*>\s*\/\/[^\n]*<\/script>/i", $source)){
			return '';
		}
		
		$source = preg_replace_callback("/([a-z]{4,5}\:)?\/\/[^\n]*/", '\SpeedyCache\Enhanced::remove_single_line_comments_from_js', $source);

		$source = preg_replace("/\}\)\;[^\S\r\n]+/", "});", $source);

		$source = preg_replace("/^\s+/m", "", $source);

		
		$source = preg_replace("/\s*(\!|\=)(\={1,3})\s*/", "$1$2", $source);

		// to remove spaces at the end of the line
		$source = preg_replace("/(\D)[^\S\r\n]+\n/", "$1\n", $source);

		$source = preg_replace("/([^\[\.\?])[^\S\r\n]+\:[^\S\r\n]+([^\]\.\?])/", "$1:$2", $source);

		$source = preg_replace("/([^\s\|])[^\S\r\n]*\&\&[^\S\r\n]*([^\s\|])/", "$1&&$2", $source);
		$source = preg_replace("/([^\s\&])[^\S\r\n]*\|\|[^\S\r\n]*([^\s\&])/", "$1||$2", $source);
		// @media all and (width), maybe later we  can do preg_replace_callback()
		//b.match(/^(<div><br( ?\/), no need to remove the spage between ( and ?
		//dashArray.replace(/( *, *)/g, no need to remove the spage between ( and *
		$source = preg_replace("/[^\S\r\n]*\([^\S\r\n]+([^\?\*\+])/", "($1", $source);
		$source = preg_replace("/and\(/", "and (", $source);
		//------
		$source = preg_replace("/([^\s\=\!])[^\S\r\n]*\=[^\S\r\n]*([^\s\=\!])/", "$1=$2", $source);

		$source = preg_replace("/\)\s+\{/", "){", $source);
		$source = preg_replace("/\}\s+}/s", "}}", $source);
		$source = preg_replace("/\};\s+}/s", "};}", $source);
		$source = preg_replace("/\}\s*else\s*\{/", "}else{", $source);
		$source = preg_replace("/\}[^\S\r\n]*else[^\S\r\n]*if[^\S\r\n]*\(/", "}else if(", $source);
		$source = preg_replace("/if\s*\(\s*/", "if(", $source);
		$source = preg_replace("/[^\S\r\n]+\)/", ")", $source);

		$source = preg_replace("/<script([^\>\<]*)>\s*/i", "<script$1>", $source);
		$source = preg_replace("/\s*<\/script>/i", "</script>", $source);

		// .name( something)
		$source = preg_replace("/(\.[A-Za-z\_]+\()\s{1,2}/", "$1", $source);

		// Muli-Line Comments Start
		$source = preg_replace_callback("/\/\*(.*?)\*\//s", '\SpeedyCache\Enhanced::remove_multi_line_comments_from_js', $source);
		// END

		$source = str_replace("\xEF\xBB\xBF", '', $source);

		$source = preg_replace("/^\s+/m", '', $source);

		//<script><!--
		//var x=5;
		//</script>
		if(!empty($inline_js)){
			if(preg_match("/<script[^\>]*><\!--/i", $source)){
				if(!preg_match("/-->/i", $source)){
					$source = preg_replace("/(<script[^\>]*>)<\!--\n/i", "$1", $source);
				}
			}
		}

		return $source;
	}

	static function minify_inline_js($data){
		global $speedycache;
		
		$script_list = array();
		$script_start_index = false;

		for($i = 0; $i < strlen( $data ); $i++){
			if(isset($data[$i - 6])){
				if(substr($data, $i - 6, 7) == '<script'){
					$script_start_index = $i - 6;
				}
			}

			if(isset($data[$i - 8])){
				if($script_start_index){
					if(substr($data, $i - 8, 9) == '</script>'){
						array_push($script_list, array('start' => $script_start_index, 'end' => $i));
						$script_start_index = false;
					}
				}
			}
		}

		if(!empty($script_list)){
			foreach(array_reverse($script_list) as $key => $value){
				$inline_script = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));
				
				if(preg_match("/google\_ad\_slot/i", $inline_script)){
					$speedycache->enhanced['inline_scripts'] = $speedycache->enhanced['inline_scripts'].$inline_script;
					continue;
				}

				if(preg_match("/<script[^\>]+src=[\'\"][^\>]+>/i", $inline_script)){
					continue;
				}

				if(preg_match("/<script[^\>]+text\/template[^\>]+>/i", $inline_script)){
					continue;
				}

				$speedycache->enhanced['inline_scripts'] = $speedycache->enhanced['inline_scripts'].$inline_script;
					
				$inline_script = \SpeedyCache\Enhanced::minify_js($inline_script, true);

				$inline_script = str_replace(' type="text/javascript"', '', $inline_script);
				$inline_script = str_replace(' type="text/javascript"', '', $inline_script);

				$speedycache->enhanced['inline_scripts'] = $speedycache->enhanced['inline_scripts'].$inline_script;

				$data = substr_replace($data, $inline_script, $value['start'], ($value['end'] - $value['start'] + 1));

			}
		}

		return $data;
	}

	static function remove_multi_line_comments_from_js($matches){

		//segs.unshift('//*[@id="' + elm.getAttribute('id') + '"]');
		if(preg_match("/\/\*\[\@/", $matches[0])){
			return $matches[0];
		}
		
		if(preg_match("/\/\*\@cc_on/i", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/\.exec\(|\.test\(|\.match\(|\.search\(|\.replace\(|\.split/", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/function\(/", $matches[0])){
			return $matches[0];
		}

		//c("unmatched `/*`");
		if(preg_match("/^\/\*\`\"\)\;/", $matches[0])){
			return $matches[0];
		}

		// <script type='text/javascript'>
		// /* <![CDATA[ */
		// var icegram_data = {"custom_js":"<script type=\"text\/javascript\">\/* add your js code here *\/ <\/script>"};
		// /* ]]> */
		// </script>
		if(preg_match("/\\/script>/", $matches[0]) && preg_match("/\*\\//", $matches[0])){
			return $matches[0];
		}

		// {comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t]+.+)*/m,lookbehind:!0}}
		if(preg_match("/\.\+\)\*\//", $matches[0])){
			return $matches[0];
		}

		// var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
		if(preg_match("/\/\*\\\\n\/\/\#\s+sourceURL/i", $matches[0])){
			return $matches[0];
		}

		// function(e){return"/*# sourceURL=".concat(r.sourceRoot).concat(e," */")
		if(preg_match("/\/\*\#\s+sourceURL/i", $matches[0])){
			return $matches[0];
		}

		// /*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(o))))," */
		if(preg_match("/\/\*\#\s+sourceMappingURL/i", $matches[0])){
			return $matches[0];
		}

		// var COMMON_HEADERS = {'Accept': 'application/json, text/plain, */*'};
		if(preg_match("/\/\*\'\}\;/", $matches[0])){
			return $matches[0];
		}

		return '';
	}

	static function remove_single_line_comments_from_js($matches){
		if(preg_match("/\n\/\/[^\n]+/", $matches[0])){
			// // */
			if(preg_match("/\/\/\s*\*\//", $matches[0])){
				return $matches[0];
			}

			return '';
		}

		// // something */
		if(preg_match("/\/\/[^\n\t]*\*\//", $matches[0])){
			return $matches[0];
		}

		// var url = {"name" : "something",
		// 		   "url"  : '//$1/p/$2/media/?size=l'
		// 		  };
		if(preg_match("/\'\h*$/", $matches[0])){
			if(substr_count($matches[0], "'") == 1){
				return $matches[0];
			}
		}

		// ia=/^\.\//;x=Object.prototype;var K=x.toString,
		if(preg_match("/^\/\/\;/", $matches[0])){
			return $matches[0];
		}

		// var snd = new Audio("data:audio/wav;base64,//uQRAAAAWMSLwUIYAAsYkXgoQw3kuZGUAAAAAAAAAACU=");
		if(preg_match("/^\/\/[A-Za-z0-9\+\/\=]+[\'\"]\)\;/", $matches[0])){
			return $matches[0];
		}

		// "data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==":"about:blank",
		if(preg_match("/^\/\/w\=\=\"/", $matches[0])){
			return $matches[0];
		}


		// var div = {"background-image":"url(data:image/png;base64,wD/AP+gvatMW2UYx//POaRK5CYII=)"};
		if(preg_match("/^\/\/[A-Za-z0-9\+\/\=]+\)[\'\"]\}/", $matches[0])){
			return $matches[0];
		}

		// base64
		if(preg_match("/^\/\/[A-Za-z0-9\+\/\=]{150}/", $matches[0])){
			return $matches[0];
		}

		// var a = '<a href="javascript://" id="nextLink" title="' + opts.strings.nextLinkTitle + '"></a>';
		if(preg_match("/^cript\:\/\/\"/", $matches[0])){
			return $matches[0];
		}

		// url.replace( /^http:\/\//i, 'https://' );
		//domain = domain.replace(new RegExp(/^http\:\/\/|^https\:\/\/|^ftp\:\/\//i),"");
		if(preg_match("/^\/\/i(\,|\))/", $matches[0])){
			return $matches[0];
		}

		// {pattern:/\/\*[\*!][\s\S]*?\*\//gm,alias:"co2"}
		// d=b?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;
		// replace(/\//g,"")
		// e.match(/^https?:\/\//g)
		if(preg_match("/^\/\/gm?(\,|\)|\;)/", $matches[0])){
			return $matches[0];
		}

		// match(/^https?:\/\//)
		// var pattern = RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?");
		if(preg_match("/^\/\/(\)|\()/", $matches[0])){
			return $matches[0];
		}

		//src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
		if(preg_match("/^\/\/about\:blank/", $matches[0])){
			return $matches[0];
		}

		//"<img src='http"+(location.href.indexOf('https:')==0?'s://www':'://track')+".websiteceo.com/m/?"+q+"' width='1' height='1' border='0' align='left'>";
		if(preg_match("/^\/\/www\'/", $matches[0])){
			return $matches[0];
		}

		// if(URL.match( /^https?:\/\// ) ){
		if(preg_match("/^\/\/\s*\)\s*\)\s*\{/", $matches[0])){
			return $matches[0];
		}

		// "string".replace(/\//,3);
		if(preg_match("/^\/\/\s*\,/", $matches[0])){
			return $matches[0];
		}

		// src = src.replace('https?://[^./].','');
		if(preg_match("/^\/\/\[[^\]\[]+\]/", $matches[0])){
			return $matches[0];
		}

		// comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,
		if(preg_match("/^\/\/\s*gi\s*\,/", $matches[0])){
			return $matches[0];
		}

		// var proto = document.location.protocol, host = "whatshelp.io", url = proto + "//static." + host;
		if(preg_match("/^\/\/static\./i", $matches[0])){
			return $matches[0];
		}

		// whatsapp://send?text=
		// NOTE: preg_match_replace gets only 5 chars so we check "tsapp://" instead of "whatsapp://"
		if(preg_match("/^tsapp\:\/\/send/", $matches[0])){
			return $matches[0];
		}

		// sms://?&body="+postTitle+" "+postUrl
		if(preg_match("/^\/\/\?\&/", $matches[0])){
			return $matches[0];
		}

		// viber://forward?text="+postTitle+" "+postUrl
		if(preg_match("/^viber\:\/\//", $matches[0])){
			return $matches[0];
		}

		//threema://compose?text="+postTitle+" "+postUrl
		if(preg_match("/^reema\:\/\//", $matches[0])){
			return $matches[0];
		}

		// weixin://
		if(preg_match("/^eixin\:\/\//", $matches[0])){
			return $matches[0];
		}

		// fb-messenger://share?
		if(preg_match("/^enger\:\/\//", $matches[0])){
			return $matches[0];
		}

		// rtmp://37.77.2.234:1935/redirect/live.flv
		if(preg_match("/^rtmp\:\/\//", $matches[0])){
			return $matches[0];
		}

		// comgooglemaps://?q=40.956572,29.0859053&directionsmode=driving
		if(preg_match("/^emaps\:\/\//", $matches[0])){
			return $matches[0];
		}

		// javascript://
		if(preg_match("/^cript\:\/\//", $matches[0])){
			return $matches[0];
		}

		// jsFileLocation:"//29.59.155.173/~cfo/site-data/plugins/revslider/public/assets/js/",
		if(preg_match("/^\/\/([0-9]{1,3}\.){3}[0-9]{1,3}\/\~/", $matches[0])){
			return $matches[0];
		}

		// var url = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
		if(preg_match("/\/\/\=\]/", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/^maps\:\/\//", $matches[0])){
			return $matches[0];
		}

		// "line://msg/text/" + postTitle + "! " + postUrl
		if(preg_match("/^line\:\/\//", $matches[0])){
			return $matches[0];
		}

		// document.write('<script defer src="//:"></script>');
		if(preg_match("/^\/\/\:\"/", $matches[0])){
			return $matches[0];
		}

		// url: "//$1/p/$2/media/?size=l"
		if(preg_match("/^\/\/\\$/", $matches[0])){
			return $matches[0];
		}
		
		if(preg_match("/^\/\/\//", $matches[0])){
			return $matches[0];
		}
		
		if(preg_match("/^http/", $matches[0])){
			return $matches[0];
		}

		// var xxx={"case":"\nhttp://www.google.com"};
		if(preg_match("/^nhttp/", $matches[0])){
			return $matches[0];
		}

		// var currUrl = 'file://' + "something";
		if(preg_match("/^file\:\/\//i", $matches[0])){
			return $matches[0];
		}

		//<a href="javascript://nop/" class="morelink">
		if(preg_match("/cript\:\/\/nop/i", $matches[0])){
			return $matches[0];
		}

		// Flash.RTMP_RE = /^rtmp[set]?:\/\//i;
		if(preg_match("/^\/\/i\;/", $matches[0])){
			return $matches[0];
		}

		//segs.unshift('//*[@id="' + elm.getAttribute('id') + '"]');
		if(preg_match("/^\/\/\*\[/", $matches[0])){
			return $matches[0];
		}

		// e.write('<!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">')
		if(preg_match("/^\/\/W3C\/\/DTD\s+XHTML/i", $matches[0])){
			return $matches[0];
		}

		// var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
		// var xxx = "} catch (e){ throw 'TemplateError: ' + e + ' (on " + name + "' + ' line ' + this.line + ')'; } " + "//@ sourceURL=" + name + "\n" // source map
		if(preg_match("/^\/\/(\#|\@)\s+sourceURL/i", $matches[0])){
			return $matches[0];
		}

		// options.tileLayerThem = '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
		if(preg_match("/^\/\/\{[^\}]+\}\./", $matches[0])){
			return $matches[0];
		}

		// document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_pixastic__\"></"+"script>");
		if(preg_match("/^\/\/\:\\\\(\"|\')/", $matches[0])){
			return $matches[0];
		}

		// a.src='//cdn.'+w[r+'h']+'/libs/b.js';
		if(preg_match("/^\/\/cdn\./", $matches[0])){
			return $matches[0];
		}

		//<!DOCTYPE svg "-//W3C//DTD SVG 1.1//EN
		if(preg_match("/^\/\/W3C/i", $matches[0])){
			return $matches[0];
		}

		/*
		//# sourceMappingURL=angular.min.js.map
		//# sourceMappingURL=data:application
		*/
		if(preg_match("/sourceMappingURL\s*\=\s*(angular\.min\.js\.map|data\:application)/i", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/\.exec\(|\.test\(|\.match\(|\.search\(|\.replace\(|\.split/", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/^\/\/(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}/", $matches[0])){
			return $matches[0];
		}

		if(preg_match("/\'|\"/", $matches[0])){
			// ' something
			if(preg_match("/^\/\/\s*[\'|\"]/", $matches[0])){
				return $matches[0];
			}

			// new Validator.Assert().Regexp('(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)', 'i');
			if(preg_match("/[\'\"]\,\s*[\'\"]i[\'\"]\)\;/", $matches[0])){
				return $matches[0];
			}

			/*static function speedycache_powerful_html_Uc(a,b){var c=Q&&Q.isAvailable(),d=c&&!(nb.kd||!0===nb.get("previous_websocket_failure"));b.ce&&(c||L("
			wss:// URL used, but browser isn't known to support websockets.  Trying anyway."),d=!0);if(d)a.Mb=[Q];else{var e=a.Mb=[];Vb(Vc,function(a,b){b&&b.isAvailable()&&e.push(b)})}}static function speedycache_powerful_html_Wc(a){if(0<a.Mb.length)return a.Mb[0];throw Error("No transports available");};static function speedycache_powerful_html_Xc(a,b,c,d,e,f){this.id=a;this.e=Mb("c:"+this.id+":");this.Lc=c;this.Ab=d;this.S=e;this.Kc=f;this.M=b;this.fc=[];this.Zc=0;this.yd=new Tc(b);this.ma=0;this.e("Connection created");Yc(this)}
			*/
			if(preg_match("/if\(/", $matches[0]) && preg_match("/this\./", $matches[0]) && preg_match('/function/', $matches[0])){
				return $matches[0];
			}

			// <script defer src="//:" id="__onload_ie_pixastic__">\x3c/script>
			if(preg_match("/x3c\/script>/i", $matches[0])){
				return $matches[0];
			}

			return '';
		}

		if(preg_match("/<\/script>/", $matches[0])){
			return preg_replace("/\/\/[^\<]+<\/script>/", '</script>', $matches[0]);
		}

		return '';
	}

	static function minify_js_in_body($exclude_rules = false){
		global $speedycache;
		
		$data = $speedycache->enhanced['html'];
		$script_list = array();
		$script_start_index = false;

		for($i = 0; $i < strlen( $data ); $i++){
			if(isset($data[$i - 6])){
				if(substr($data, $i - 6, 7) == '<script'){
					$script_start_index = $i - 6;
				}
			}

			if(isset($data[$i - 8]) && !empty($script_start_index)){
				if(substr($data, $i - 8, 9) == '</script>'){
					array_push($script_list, array('start' => $script_start_index, 'end' => $i));
					$script_start_index = false;
				}
			}
		}

		if(empty($script_list)){
			return $speedycache->enhanced['html'];
		}
		
		foreach(array_reverse($script_list) as $key => $value){
			$script_tag = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));

			if(!preg_match("/^<script[^\>\<]+src\=[^\>\<]+>/i", $script_tag) && preg_match("/\/speedycache\-assets\//i", $script_tag)){
				continue;
			}

			preg_match("/src\=[\"\']([^\'\"]+)[\"\']/i", $script_tag, $src);

			$http_host = str_replace(array('http://', 'www.'), '', sanitize_text_field($_SERVER['HTTP_HOST']));
			
			if(!isset($src[1])){
				continue;
			}

			if(!preg_match('/'.preg_quote($http_host, '/').'/i', $src[1])){
				continue;
			}

			if(!empty($exclude_rules)){
				$is_excluded = false;

				foreach((array)$exclude_rules as $exclude_key => $exclude_value){
					if(!empty($exclude_value['prefix']) && $exclude_value['type'] === 'js'){
						if($exclude_value['prefix'] === 'contain'){
							$preg_match_rule = preg_quote($exclude_value['content'], '/');
						}

						if(preg_match('/'.$preg_match_rule.'/i', $src[1])){
							$is_excluded = true;
							break;
						}
					}
				}

				if(!empty($is_excluded)){
					continue;
				}
			}
			
			// Skip if the file is already minified.
			if(strpos($src[1], '.min.') !== FALSE){
				continue;
			}

			if(preg_match("/alexa\.com\/site\_stats/i", $src[1])){
				continue;
			}

			if(preg_match("/wp-spamshield\/js\/jscripts\.php/i", $src[1])){
				continue;
			}

			//amazonjs/components/js/jquery-tmpl/jquery.tmpl.min.js?ver=1.0.0pre
			if(preg_match("/jquery-tmpl\/jquery\.tmpl\.min\.js/i", $src[1])){
				continue;
			}

			//<script src="https://server1.opentracker.net/?site=www.site.com"></script>
			if(preg_match("/[\?\=].*".preg_quote($http_host, '/').'/i', $src[1])){
				continue;
			}
			
			$js_file_name = md5($src[1]);

			$cache_file_path = WP_CONTENT_DIR.'/'.$speedycache->enhanced['cache_speedycache_minified'].'/'.$js_file_name;
			
			if(!defined('SPEEDYCACHE_WP_CONTENT_URL')){
				$js_script = content_url().'/'.$speedycache->enhanced['cache_speedycache_minified'].'/'.$js_file_name;
			}else{
				$js_script = SPEEDYCACHE_WP_CONTENT_URL.'/'.$speedycache->enhanced['cache_speedycache_minified'].'/'.$js_file_name;
			}

			$js_script = str_replace(array('http://', 'https://'), '//', $js_script);
			
			$args = array(
				'src' => $src[1],
				'cache_file_path' => $cache_file_path,
				'js_script' => $js_script,
				'script_tag' => $script_tag,
				'value' => $value
			);
			
			self::fetch_and_minify_js($args);
		}

		return $speedycache->enhanced['html'];
	}


	static function fetch_and_minify_js($args){
		global $speedycache;
		
		$response = wp_remote_get(\SpeedyCache\Enhanced::fix_protocol($args['src']), array('timeout' => 10 ) );

		if(empty($response) || is_wp_error($response)){
			return false;
		}

		if(wp_remote_retrieve_response_code($response) != 200){
			return false;
		}

		$js_content = wp_remote_retrieve_body($response);

		if(preg_match('/<\/\s*html\s*>\s*$/i', $js_content)){
			return false;
		}
		
		$minified_js_content = \SpeedyCache\Enhanced::minify_js($js_content);

		if(!is_dir($args['cache_file_path'])){
			$prefix = time();
			\SpeedyCache\Cache::create_dir($args['cache_file_path'], $minified_js_content, 'js');
		}

		if(file_exists($args['cache_file_path']) && $js_files = @scandir($args['cache_file_path'], 1)){
			$new_script = str_replace($args['src'], $args['js_script'].'/'.$js_files[0], $args['script_tag']);
			$speedycache->enhanced['html'] = substr_replace($speedycache->enhanced['html'], $new_script, $args['value']['start'], ($args['value']['end'] - $args['value']['start'] + 1));
		}

	}

	static function combine_js_in_footer($minify = false){
		global $speedycache;
		
		$footer = strstr($speedycache->enhanced['html'], '<!--SPEEDYCACHE_FOOTER_START-->');

		\SpeedyCache\JS::init($footer, $minify);
		$tmp_footer = \SpeedyCache\JS::combine();
		
		if(!empty($speedycache->options['render_blocking'])){
			\SpeedyCache\RenderBlocking::init($tmp_footer);
			$tmp_footer = \SpeedyCache\RenderBlocking::action(false, true);
		}
		
		$speedycache->enhanced['html'] = str_replace($footer, $tmp_footer, $speedycache->enhanced['html']);
		
		return $speedycache->enhanced['html'];
	}
	/* Js Part End */

	static function fix_protocol($url){
		if(!preg_match('/^\/\//', $url)){
			return $url;
		}

		if(preg_match('/^https:\/\//', home_url())){
			return 'https:'.$url;
		}

		return 'http:'.$url;
	}

	static function set_html($html){
		global $speedycache;
		
		$speedycache->enhanced['html'] = $html;
		self::set_head_html();
		self::set_body_html();
	}

	static function set_body_html(){
		global $speedycache;
		
		preg_match("/<body(.+)<\/body>/si", $speedycache->enhanced['html'], $out);

		if(isset($out[0])){
			$speedycache->enhanced['body_html'] = $out[0];
			return;
		}

		$speedycache->enhanced['body_html'] = '';
	}

	static function set_head_html(){
		global $speedycache;
		
		preg_match("/<head(.+)<\/head>/si", $speedycache->enhanced['html'], $out);

		if(isset($out[0])){
			$speedycache->enhanced['head_html'] = $out[0];
			return;
		}

		$speedycache->enhanced['head_html'] = '';

	}
	
	static function delay_js($content){
		global $speedycache;

		// If Delay js mode is selected and the scripts are empty then return
		if(empty($speedycache->options['delay_js_mode']) || (!empty($speedycache->options['delay_js_mode']) && $speedycache->options['delay_js_mode'] == 'selected' && empty($speedycache->options['delay_js_scripts']))){
			return $content;
		}
		
		$scripts = self::find_tags('<script', '</script>', $content);
		
		if(empty($scripts)){
			return $content;
		}

		foreach($scripts as $tag => $script){
			// Dont process a tag without src
			$is_inline = false;
			
			if(strpos($script['text'], ' src') === FALSE){
				$is_inline = true;
			}
			
			// We dont want to delay structured data
			if(strpos($script['text'], 'application/ld+json') !== FALSE){
				continue;
			}

			if(strpos($script['text'], 'text/template') !== FALSE){
				continue;
			}
			
			// Don't delay a module.
			if(strpos($script['text'], 'type="module"') !== FALSE){
				continue;
			}
			
			// Don't touch any import maps as they are meant to be loaded early.
			if(strpos($script['text'], 'importmap') !== FALSE){
				continue;
			}

			// We dont want to delay jQuery
			if(preg_match('/jquery\./U', $script['text'], $match)){
				continue;
			}

			// Excluding Scripts
			if($speedycache->options['delay_js_mode'] == 'all' && !empty($speedycache->options['delay_js_excludes'])){
				foreach($speedycache->options['delay_js_excludes'] as $to_delay){
					if(empty($to_delay)){
						continue;
					}

					if(strpos($script['text'], trim($to_delay)) !== FALSE){
						continue 2;
					}
				}
			}

			// Delay Selected Scripts
			if($speedycache->options['delay_js_mode'] == 'selected' && !empty($speedycache->options['delay_js_scripts'])){
				$script_found = false;
				foreach($speedycache->options['delay_js_scripts'] as $to_delay){
					if(empty($to_delay)){
						continue;
					}

					if(strpos($script['text'], trim($to_delay)) !== FALSE){
						$script_found = true;
						break;
					}
				}

				if(empty($script_found)){
					continue;
				}
			}

			$new_tag = self::updating_tag($script['text'], $is_inline);

			if(!empty($new_tag)){
				$content = str_replace($script['text'], $new_tag, $content);
			}
		}
		
		// Adds the script which loads the JS files on user interaction
		self::inject_js($content);

		return $content;

	}
	
	static function updating_tag($tag, $is_inline){
		global $speedycache;
	
		if(preg_match('/src=["\'](.*)["\']/U', $tag, $src)){
			return '<script type="speedycache/javascript" data-src="' . esc_url($src[1]) . '"></script>';
		}

		if($is_inline){
			// taking out the attributes
			preg_match_all('/<script([^>]+)?>/i', $tag, $matches);

			$attributes = [];
			// Parsing the attributes
			if(!empty($matches)){
				foreach($matches[1] as $attr_str){
					preg_match_all('/(\w+)(?:=["\']([^"\']*)["\'])?/i', trim($attr_str), $attrs, PREG_SET_ORDER);

					foreach($attrs as $attr){
						$attributes[$attr[1]] = $attr[2] ?? true;
					}
				}
			}

			// Adding our delayjs type
			$attributes['type'] = 'speedycache/javascript';
			
			// Rebulding the attributes
			$script_attr = '';
			foreach($attributes as $name => $value){
				$script_attr .= ' ' . esc_attr($name).'="'.esc_attr($value).'"';
			}

			return preg_replace('/<script([^>]+)?>/i', '<script'.$script_attr.'>', $tag);
		}
		
	}
	
	static function inject_js(&$content){
		$js = file_get_contents(SPEEDYCACHE_PRO_DIR . '/assets/js/delayjs.min.js');

		$js = '<script>'.$js.'</script>';
		$content = str_replace('</body>', $js . "\n</body>", $content);
	}
	
	static function find_tags($start_string, $end_string, $html = false){
		global $speedycache;

		if(!empty($html)){
			$data = $html;
		}

		$list = array();
		$start_index = false;
		$end_index = false;

		for($i = 0; $i < strlen($data); $i++){
			if(substr($data, $i, strlen($start_string)) == $start_string){
				if(!$start_index && !$end_index){
					$start_index = $i;
				}
			}

			if(empty($start_index) || $i < $start_index){
				continue;
			}

			if(substr($data, $i, strlen($end_string)) !== $end_string){
				continue;
			}
			
			$end_index = $i + strlen($end_string) - 1;
			$text = substr($data, $start_index, ($end_index - $start_index + 1));

			if($html === false){
				$tag = self::get_tags($start_index, $text, $end_index);

				if($tag !== FALSE){
					array_push($list, $tag);
				}
			}else{
				array_push($list, array('start' => $start_index, 'end' => $end_index, 'text' => $text));
			}

			$start_index = false;
			$end_index = false;
		}

		return $list;
	}
	
	// Adds Image dimensions to the images where height and width is not present
	// It helps in reducing the Cumulative Layout shift(CLS) as the browser knows how much space to allocate for the image.
	static function image_dimensions($content){
		
		if(!function_exists('getimagesize')){
			return $content;
		}
		
		// Get Images without height and width
		$images_regex = '<img(?:[^>](?!height=[\'\"](?:\S+)[\'\"]))*+>|<img(?:[^>](?!width=[\'\"](?:\S+)[\'\"]))*+>';

		preg_match_all('/'.$images_regex.'/Uis', $content, $image_matches);

		if(empty($image_matches)){
			return $content;
		}

		$images = $image_matches[0];
		$site_url = site_url();
		
		foreach($images as $image){

			// Get the SRC
			if(!preg_match( '/\s+src\s*=\s*[\'"](?<url>[^\'"]+)/i', $image, $src_match)){
				continue;
			}
			
			$url = $src_match['url'];

			// We will proccess image which is uploaded inside wp-content
			if(strpos($url, 'wp-content') === FALSE || strpos($url, '.svg') !== FALSE || strpos($url, $site_url) === FALSE){
				continue;
			}

			$url = str_replace($site_url, '', $url);
			$image_path = str_replace('/wp-content', '', WP_CONTENT_DIR) . $url;
	
			if(!file_exists($image_path)){
				continue;
			}

			$sizes = getimagesize($image_path);

			if(empty($sizes)){
				continue;
			}

			preg_match('/<img.*\sheight=[\'\"]?(?<height>[^\'\"\s]+)[\'\"]?.*>/i', $image, $initial_height);
			preg_match('/<img.*\swidth=[\'\"]?(?<width>[^\'\"\s]+)[\'\"]?.*>/i', $image, $initial_width);

			$dimensions_attr = '';

			if(empty($initial_height['height']) && empty($initial_width['width'])){
				$dimensions_attr = $sizes[3];
			}

			if(!empty($initial_height['height']) && empty($dimensions_attr)){
				if(!is_numeric($initial_height['height'])){
					continue;
				}

				$ratio = $initial_height['height'] / $sizes[1];

				$dimensions_attr = 'width="' . (int) round($sizes[0] * $ratio) . '" height="' . $initial_height['height'] . '"';
			}

			if(!empty($initial_width['width']) && empty($dimensions_attr)){
				if(!is_numeric( $initial_width['width'])){
					continue;
				}

				$ratio = $initial_width['width'] / $sizes[0];

				$dimensions_attr = 'width="' . $initial_width['width'] . '" height="' . (int) round($sizes[1] * $ratio) . '"';
			}
			
			$changed_image = preg_replace('/\s(height|width)=(?:[\'"]?(?:[^\'\"\s]+)*[\'"]?)?/i', '', $image);
			$changed_image = preg_replace('/<\s*img/i', '<img ' . $dimensions_attr, $changed_image);

			if(!empty($changed_image)){
				$content = str_replace($image, $changed_image, $content);
			}

		}
		
		return $content;
	}
	
	// Lazy Loads HTML elements.
	static function lazy_load_html($content){
		global $speedycache;

		$content = str_replace('</head>', '<style>' . implode(',', $speedycache->options['lazy_load_html_elements']) . '{content-visibility:auto;contain-intrinsic-size:1px 1000px;}</style></head>', $content);
		
		return $content;
	}
	
	static function preload_critical_images($content){
		global $speedycache;
		
		preg_match_all('#(<picture.*?)?<img([^>]+?)\/?>(?><\/picture>)?#is', $content, $images, PREG_SET_ORDER);

		if(empty($images)){
			return $content;
		}

		$count = 0;
		$preload_tags = '';
		foreach($images as $image){

			// Break once the Critical Image Count is reached.
			if($count >= $speedycache->options['critical_image_count']){
				break;
			}

			if(strpos($image[0], 'secure.gravatar.com') !== FALSE){
				continue;
			}

			// NOTE:: Will remove this in future, firt we will just support <IMG> tag
			if(strpos($image[0], '<picture>') !== FALSE){
				continue;
			}

			// Excluding base64 image from preloading.
			if(strpos($image[0], ';base64') !== FALSE){
				continue;
			}

			$atts_array = wp_kses_hair($image[2], wp_allowed_protocols());
			$atts = [];

			foreach($atts_array as $name => $attr){
				$atts[$name] = $attr['value'];
			}

			if(empty($atts['src'])){
				continue;
			}
			
			// To preload unique images.
			if(strpos($preload_tags, $atts['src']) === FALSE){
				$preload_tags .= '<link rel="preload" as="image" href="'.esc_attr($atts['src']).'"'. (!empty($atts['srcset']) ? ' imagesrcset="'. esc_attr($atts['srcset']).'"' : '') . (!empty($atts['sizes']) ? 'imagesizes="'.esc_attr($atts['sizes']).'"' : '') . ' />';
			}

			$count++;
		}

		if(empty($preload_tags)){
			return $content;
		}

		// If title tag is not there then don't add the preload.
		if(strpos($content, '</title>') === FALSE){
			return $content;
		}

		$content = str_replace('</title>', '</title>' . $preload_tags, $content);

		return $content;
	}
	
	static function pre_connect_hint($urls, $relation_type){
		global $speedycache;

		if($relation_type !== 'preconnect'){
			return $urls;
		}

		foreach($speedycache->options['pre_connect_list'] as $url) {
			if(empty($url) || empty($url['resource'])){
				continue;
			}
			
			$preconnect = array('href' => $url['resource']);

			if(!empty($url['crossorigin'])){
				$preconnect['crossorigin'] = 'crossorigin'; 
			}
			
			$urls[] = $preconnect;
			
		}

		return $urls;
	}

	static function preload_resource(){
		global $speedycache;

		if(empty($speedycache->options['preload_resource_list']) || !is_array($speedycache->options['preload_resource_list'])){
			return;
		}

		foreach($speedycache->options['preload_resource_list'] as $preload_resource){
			if(empty($preload_resource['resource']) || empty($preload_resource['type'])){
				continue;
			}

			$crossorigin = '';
			if(!empty($preload_resource['crossorigin'])){
				$crossorigin = 'crossorigin';
			}

			echo '<link rel="preload" href="'.esc_url_raw($preload_resource['resource']).'" as="'.esc_attr($preload_resource['type']).'" '.esc_attr($crossorigin) .'/>';
		}
	}

}
unusedcss.php000064400000016717151526435100007307 0ustar00<?php

/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('Hacking Attempt');
}

class UnusedCss extends CommonCss{

	static function generate($urls){
		global $speedycache;

		$time = time() + 50;
		set_time_limit(60);
		
		$api = self::get_endpoint(true);
		
		if(empty($urls)){
			self::log('speedycache_unused_css_logs', 'URL not found');
			return false;
		}

		if(empty($speedycache->license['license'])){
			self::log('speedycache_unused_css_logs', 'License Not found, please link your License');
			return false;
		}

		foreach($urls as $url){
			// Handeling php timeout here
			if($time < time()){
				$urls = array_diff($urls, $attempted_url);
				self::schedule('speedycache_unused_css', $urls);
				return;
			}

			$url = trim($url, '/');
			$license = strpos($speedycache->license['license'], 'SPDFY') !== 0 ? '' : $speedycache->license['license'];
			$attempted_url[] = $url;

			$response = wp_remote_post($api, array(
				'timeout' => 30,
				'body' => array(
					'url' => $url,
					'license' => $license,
					'excludes' => !empty($speedycache->options['unused_css_exclude_stylesheets']) ? json_encode($speedycache->options['unused_css_exclude_stylesheets']) : '',
					'include_selectors' => !empty($speedycache->options['speedycache_unusedcss_include_selector']) ? json_encode($speedycache->options['speedycache_unusedcss_include_selector']) : '',
				),
				'sslverify' => false,
			));

			if(is_wp_error($response)){
				$error = $response->get_error_message();
				self::log('speedycache_unused_css_logs', $response->get_error_message(), $url);
				continue;
			}

			$body = json_decode(wp_remote_retrieve_body($response), true);

			if(empty($body)){
				$error = __('The response recieved is empty.', 'speedycache');
				self::log('speedycache_unused_css_logs', __('The response recieved is empty.', 'speedycache'), $url);
				continue;
			}

			if(empty($body['success'])){
				$error = !empty($body['message']) ? wp_strip_all_tags($body['message']) : __('Unable to extract UsedCSS', 'speedycache');
				self::log('speedycache_unused_css_logs', !empty($body['message']) ? wp_strip_all_tags($body['message']) : __('Unable to extract UsedCSS', 'speedycache'), $url);
				continue;
			}

			if(empty($body['css']) || strlen($body['css']) < 20){
				$error = __('Was unable to generate Used CSS', 'speedycache');
				self::log('speedycache_unused_css_logs', __('Was unable to generate Used CSS', 'speedycache'), $url);
				continue;
			}

			self::update_css($url, $body['css']);

			self::log('speedycache_unused_css_logs', 'success', $url); //Updates the log on success
			
			if(!empty($error)){
				return $error;
			}

			return true;
		}
	}
	
	// Adds the generated css and asynchronyses the css includes
	static function update_css($url, $css){
		global $speedycache;

		if(empty($url)){
			return false;
		}
		
		if(empty($css)){
			return false;
		}

		$css = '<style id="speedycache-used-css">'. "\n". wp_strip_all_tags($css) . '</style>';

		$url = parse_url($url);
		$uri = !empty($url['path']) ?  $url['path'] : '';
		$cache_loc = $uri . '/index.html';

		if(empty($cache_loc)){
			return;
		}
		
		if(!empty($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'SpeedyCacheTest'){
			$cache_path = speedycache_cache_path('test' . $cache_loc);
		} else {
			$cache_path = speedycache_cache_path('all' . $cache_loc);
		}
		
		$cache_path = rtrim($cache_path, '/');
		
		// For Desktop
		\SpeedyCache\UnusedCss::update_cached($cache_path, $css);

		if(!empty($speedycache->options['mobile_theme']) && $_SERVER['HTTP_USER_AGENT'] !== 'SpeedyCacheTest'){
			$cache_mobile = speedycache_cache_path('mobile-cache' . $cache_loc);

			// For Mobile Cache
			if(file_exists($cache_mobile)){
				\SpeedyCache\UnusedCss::update_cached($cache_mobile, $css);
			}
		}
	}

	// Updates the content of the cached file
	static function update_content($content, $css){
		global $speedycache;

		// Includes the Used CSS file in the head.
		$content = str_replace('</title>', '</title>' . $css, $content);

		$css_links = '/(?=<link[^>]*\s(rel\s*=\s*[\'"]stylesheet["\']))<link[^>]*\shref\s*=\s*[\'"]([^\'"]+)[\'"](.*)>/iU';
		
		preg_match_all($css_links, $content, $matches, PREG_SET_ORDER, 0);
		
		if(empty($matches)){
			return $content;
		}
		
		$exclude_stylesheets = array(
			'/widget-google-reviews/assets/css/public-main.css',
			'/uploads/elementor/css/post-',
			'/uploads/oxygen/css/',
			'/uploads/bb-plugin/cache/',
			'/et-cache/',
			'woocommerce-smallscreen.css',
			'dashicons.min.css',
			'animations.min.css',
			'/uploads/generateblocks/',
			'woocommerce-mobile.min.css',
			'fonts.googleapis.com',
		);
		
		// Mergeing user added excludes which the one we have.
		if(!empty($speedycache->options['unused_css_exclude_stylesheets']) && !is_array($speedycache->options['unused_css_exclude_stylesheets'])){
			$exclude_stylesheets = array_merge($exclude_stylesheets, $speedycache->options['unused_css_exclude_stylesheets']);
		}
		
		$noscript_wrap = '';
		
		foreach($matches as $tag){

			foreach($exclude_stylesheets as $style){
				if(strpos($tag[0], $style) !== FALSE){
					continue 2;
				}
			}
			
			// We dont want to delay te Used CSS file
			if(strpos($tag[0], 'unused-css') !== FALSE){
				continue;
			}

			// Removing the styles after getting unused css
			if(!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] === 'remove'){
				$content = str_replace($tag[0], '', $content);		
			} elseif(!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] === 'interaction'){
				$new_tag = preg_replace('#href=([\'"]).+?\1#', 'data-spcdelay="' . $tag[2] . '"',$tag[0]);
			
				$content = str_replace($tag[0], $new_tag, $content);
				
				$noscript_wrap .= $tag[0];
			} else {
				// Loading the Unused CSS Async
				$preload = str_replace('stylesheet', 'preload', $tag[1]);
				$onload = preg_replace('~' . preg_quote($tag[3], '~') . '~iU', ' as="style" onload="" ' . $tag[3] . '>', $tag[3]);

				$new_tag = str_replace($tag[3] . '>', $onload, $tag[0]);
				$new_tag = str_replace($tag[1], $preload, $new_tag);
				$new_tag = str_replace('onload=""', 'onload="this.onload=null;this.rel=\'stylesheet\'"', $new_tag);
				$new_tag = preg_replace('/(id\s*=\s*[\"\'](?:[^\"\']*)*[\"\'])/i', '', $new_tag);

				$content = str_replace($tag[0], $new_tag, $content);
				
				$noscript_wrap .= $tag[0];
			}
		}
		
		if(!empty($noscript_wrap)){
			$noscript_wrap .= '</noscript>';
			
			if(!empty($speedycache->options['unusedcss_load']) && $speedycache->options['unusedcss_load'] === 'interaction'){
				$noscript_wrap .= '<script type="text/javascript" id="speedycache-delayed-styles">!function(){const e=["keydown","mousemove","wheel","touchmove","touchstart","touchend"];function t(){document.querySelectorAll("link[data-spcdelay]").forEach(function(e){e.setAttribute("href",e.getAttribute("data-spcdelay"))}),e.forEach(function(e){window.removeEventListener(e,t,{passive:!0})})}e.forEach(function(e){window.addEventListener(e,t,{passive:!0})})}();</script>';
			}
			
			$noscript_wrap = '<noscript>' . $noscript_wrap;
		
			$content = str_replace($noscript_wrap, '', $content);
			
			$content = str_replace('</body>', $noscript_wrap . '</body>', $content);
		}

		return $content;
	}
}
objectcache.php000064400000020261151526435100007512 0ustar00<?php

namespace SpeedyCache;

if(!defined('ABSPATH')){
	die('HACKING ATTEMPT!');
}

class ObjectCache{
	static $oc_driver = 'Redis';
	static $port = '6379';
	static $host = '127.0.0.1';
	static $conn;
	static $ttl = 360; // in seconds
	static $is_multisite = false;
	static $blog_id;
	static $prefix = 'speedycache';
	static $conf_file = WP_CONTENT_DIR . '/.speedycache-object.dat';
	static $conf;
	static $instance;
	static $persistent;
	static $async_flush;
	static $serialize;
	static $non_cache_group;
	
	static function get_instance(){
		if(self::$instance){
			return self::$instance;
		}

		self::$instance = new self();
		
		try{
			self::boot();
		} catch(\Exception $e){
			// Don't need to log here as the error has been already logged before, this it just to prevent error
		}

		return self::$instance;
	}

	static function boot(){
		self::$conf = self::get_conf();

		self::$host = !empty(self::$conf['host']) ? self::$conf['host'] : '127.0.0.1';
		self::$port = !empty(self::$conf['port']) ? self::$conf['port'] : '6379';
		self::$ttl = !empty(self::$conf['ttl']) ? (int) self::$conf['ttl'] : 360;
		self::$persistent = !empty(self::$conf['persistent']) ? true : false;
		self::$async_flush = !empty(self::$conf['async_flush']) ? true : false;
		self::$serialize = !empty(self::$conf['serialization']) ? self::$conf['serialization'] : 'none';
		$compress = !empty(self::$conf['compress']) ? self::$conf['compress'] : 'COMPRESSION_NONE';
		self::$non_cache_group = (!empty(self::$conf['non_cache_group']) && is_array(self::$conf['non_cache_group'])) ? self::$conf['non_cache_group'] : [];
		self::$prefix = !empty(self::$conf['hashed_prefix']) ? self::$conf['hashed_prefix'] : '';

		if(self::$host === 'localhost'){
			self::$host = '127.0.0.1';
		}
		
		if(empty(self::connect())){
			error_log('SpeedyCache: Unable to connect to Redis');
			return false;
		}
		
		try{
			
			switch(self::$serialize){
				case 'SERIALIZER_PHP':
					self::$conn->setOption(self::$conn::OPT_SERIALIZER, self::$conn::SERIALIZER_PHP);
					break;
					
				case 'SERIALIZER_IGBINARY':
					self::$conn->setOption(self::$conn::OPT_SERIALIZER, self::$conn::SERIALIZER_IGBINARY);
					break;
					
				default:
					self::$conn->setOption(self::$conn::OPT_SERIALIZER, self::$conn::SERIALIZER_NONE);
					break;
			}

			switch($compress){
				case 'COMPRESSION_NONE':
					self::$conn->setOption(self::$conn::OPT_COMPRESSION, self::$conn::COMPRESSION_NONE);
					break;
					
				case 'COMPRESSION_ZSTD':
					self::$conn->setOption(self::$conn::OPT_COMPRESSION, self::$conn::COMPRESSION_ZSTD);
					self::$conn->setOption(self::$conn::OPT_COMPRESSION_LEVEL, (string) -5);
					break;
					
				case 'COMPRESSION_LZ4':
					self::$conn->setOption(self::$conn::OPT_COMPRESSION, self::$conn::COMPRESSION_LZ4);
					break;

				case 'COMPRESSION_LZF':
					self::$conn->setOption(self::$conn::OPT_COMPRESSION, self::$conn::COMPRESSION_LZF);
					break;
					
			}

		} catch(\RedisException $e){
			error_log($e->getMessage());
			throw new \Exception($e->getMessage()); // To show on settings page
			return false;
		}

	}
	
	static function get_conf(){
		if(!file_exists(self::$conf_file)){
			return [];
		}

		$conf = file_get_contents(self::$conf_file);
		
		if(empty($conf)){
			error_log('SpeedyCache: Conf file was empty');
			return;
		}

		return json_decode($conf, true);
	}
	
	// Creates a unique id based on blogID, group and key
	static function id($key, $group){
		return self::$prefix  . ':' . self::$blog_id.$group . ':' . $key;
	}
	
	// Updates object-cache.php file at wp-content/object-cache.php
	static function update_file(){
		$file = WP_CONTENT_DIR . '/object-cache.php';
		
		if(!file_exists($file)){
			touch($file);
		}
		
		$code = '<?php

if(!defined("WPINC")){
	die();
}

if(!defined("SPEEDYCACHE_OBJECT_CACHE")){
	define("SPEEDYCACHE_OBJECT_CACHE", true);
}

$plugin_dir = (defined("WP_PLUGIN_DIR") ? WP_PLUGIN_DIR : WP_CONTENT_DIR . "/plugins") . "/speedycache-pro";
$conf_file = WP_CONTENT_DIR . "/.speedycache-object.dat";
$lib_file = $plugin_dir . "/main/object-cache-lib.php";


if(file_exists($plugin_dir) && file_exists($conf_file) && file_exists($lib_file)){
	$spdf_config = file_get_contents($conf_file);
	$spdf_config = json_decode($spdf_config, true);
	
	if (! SPEEDYCACHE_OBJECT_CACHE || (empty($spdf_config["admin"]) && defined("WP_ADMIN"))){
		wp_using_ext_object_cache(false);
	}else if (file_exists($lib_file)) {
		include_once $lib_file;
	}
}';
		file_put_contents($file, $code);

	}
	
	static function connect(){

		if(!empty(self::$conn)){
			return true;
		}
		
		if(!class_exists(self::$oc_driver)){
			error_log('SpeedyCache: The defined driver ' . self::$oc_driver . 'not present');
			return false;
		}
		
		$failed = false;
		$is_socket = false;
		
		if(strpos(self::$host, '.sock')){
			$is_socket = true;
		}

		$persistent = !empty(self::$persistent) ? 'pconnect' : 'connect';

		if(self::$oc_driver == 'Redis'){

			try {
				self::$conn = new \Redis();
				
				if($is_socket){
					self::$conn->{$persistent}(self::$host);
				} else {
					self::$conn->{$persistent}(self::$host, self::$port);
				}
				
				if(!empty(self::$conf['username']) && !empty(self::$conf['password'])){
					self::$conn->auth(['user' => self::$conf['username'], 'pass' => self::$conf['password']]);
				} else if(!empty(self::$conf['password'])){
					self::$conn->auth(self::$conf['password']);
				}

				// Testing if connection worked
				$res = self::$conn->ping();
				
				if(empty($res) && $res !== '+PONG'){
					$failed = true;
				}
				
				if(!empty($failed)){
					self::$conn = null;
					return false;
				}

				self::$conn->select((int) (!empty(self::$conf['db-id']) ? self::$conf['db-id'] : 0));

			}catch(\RedisException $e){
				error_log('SpeedyCache' . $e->getMessage());
				throw new \Exception($e->getMessage()); // To show on settings page
				return false;
			}
			catch(\Exception $e){
				error_log('SpeedyCache  ->>' . $e->getMessage());
				throw new \Exception($e->getMessage()); // To show on settings page
			}
		}
		
		return true;

	}
	
	static function set($key, $data, $expire = 0){
		
		if(empty(self::$conn)){
			return false;
		}

		$ttl = $expire ?: self::$ttl;
		
		if((is_array($data) || is_object($data)) && self::$serialize === 'none'){
			$data = serialize($data);
		}
		
		$key = self::$prefix . $key;

		try{
			$res = self::$conn->setEx($key, $ttl, $data);
		} catch (\RedisException $ex) {
			error_log($ex->getMessage());
		}
	}
	
	static function get($key){
		
		if(empty(self::$conn)){
			return false;
		}
		
		$key = self::$prefix . $key;

		try{
			return self::$conn->get($key);
		}catch(\RedisException $e){
			error_log($e->getMessage());
			return false;
		}
	}
	
	static function exists($key){
		
		if(empty(self::$conn)){
			return false;
		}
		
		$key = self::$prefix . $key;

		try{
			return self::$conn->exists($key);
		}catch(\RedisException $e){
			error_log($e->getMessage());
			return false;
		}
	}
	
	static function delete($key){
		
		$del = self::$async_flush ? 'unlink' : 'del';

		if(empty(self::$conf['enable'])){
			return false;
		}
		
		if(empty(self::$conn)){
			return false;
		}

		$key = self::$prefix . $key;

		try{
			self::$conn->{$del}($key);
		} catch(\RedisException $e){
			error_log($e->getMessage());
			return false;
		}
	}
	
	static function get_memory(){
		self::boot();
		
		if(empty(self::$conn)){
			return 'None';
		}
		
		try{
			$memory = self::$conn->info('memory');
		} catch(\RedisException $e){
			error_log($e->getMessage());
			return 'None';
		}
		
		if(!empty($memory['used_memory'])){
			return size_format($memory['used_memory']);
		}

		return 'None';
	}
	
	// Flushes whole database
	static function flush_db($sync = true){
		if(empty(self::$conf['enable'])){
			return false;
		}

		if(empty(self::$conn)){
			return false;
		}
		
		try{
			return self::$conn->flushDb($sync);
		} catch(\RedisException $e){
			error_log($e->getMessage());
			return false;
		}
	}

}