"Manage in the Dashboard" -> "Select a retrieval way:" ('Direct' or 'WP Remote Post')
     *
	 * @var string
	 */
	public static $domGetType = 'direct';
	/**
	 * Record them for debugging purposes when using /?wpacu_debug
	 *
	 * @var array
	 */
	public $allUnloadedAssets = array( 'styles' => array(), 'scripts' => array() );
	/**
	 * @var array
	 */
	public $globalUnloaded = array();
	/**
	 * @var array
	 */
	public $loadExceptionsPageLevel = array( 'styles' => array(), 'scripts' => array(), '_set' => false );
	/**
	 * @var array[]
	 */
	public $loadExceptionsPostType = array( 'styles' => array(), 'scripts' => array(), '_set' => false );
	/**
	 * Rule that applies site-wide: if the user is logged-in
	 *
	 * @var array
	 */
	public $loadExceptionsLoggedInGlobal = array( 'styles' => array(), 'scripts' => array(), '_set' => false );
	/**
	 * @var
	 */
	public $fetchUrl;
    // [wpacu_lite]
    /**
     * @var
     */
    public $isUpdateable = true;
	// [/wpacu_lite]
    /**
	 * @var int
	 */
	public $currentPostId = 0;
	/**
	 * @var array
	 */
	public $currentPost = array();
	/**
	 * @var array
	 */
	public static $vars = array( 'woo_url_not_match' => false, 'is_woo_shop_page' => false, 'for_type' => '', 'current_post_id' => 0, 'current_post_type' => '' );
	/**
	 * This is set to `true` only if "Manage in the Front-end?" is enabled in plugin's settings
	 * and the logged-in administrator with plugin activation privileges
	 * is outside the Dashboard viewing the pages like a visitor
	 *
	 * @var bool
	 */
	public $isFrontendEditView = false;
	/**
	 * @var array
	 */
	public $stylesInHead = array();
	/**
	 * @var array
	 */
	public $scriptsInHead = array();
	/**
	 * @var array
	 */
	public $assetsInFooter = array( 'styles' => array(), 'scripts' => array() );
	/**
	 * @var array
	 */
	public $wpAllScripts = array();
	/**
	 * @var array
	 */
	public $wpAllStyles = array();
	/**
	 * @var array
	 */
	public $ignoreChildren = array();
	/**
	 * @var array
	 */
	public $ignoreChildrenHandlesOnTheFly = array();
	/**
	 * @var int
	 */
	public static $wpStylesSpecialDelimiters = array(
		'start' => ''
	);
	/**
	 * @var array
	 */
	public $postTypesUnloaded = array();
	/**
	 * @var array
	 */
	public $settings = array();
	/**
	 * @var bool
	 */
	public $isAjaxCall = false;
	/**
	 * Fetch CSS/JS list from the Dashboard
	 *
	 * @var bool
	 */
	public $isGetAssetsCall = false;
	/**
	 * Populated in the Parser constructor
	 *
	 * @var array
	 */
	public $skipAssets = array( 'styles' => array(), 'scripts' => array() );
	/**
     * For these handles, it's strongly recommended to use 'Ignore dependency rule and keep the "children" loaded'
     * if any of them are unloaded in any page
     *
	 * @var \string[][]
	 */
	public $keepChildrenLoadedForHandles = array(
		'css' => array(
            'elementor-icons'
        ),
        'js'  => array(
            'swiper',
            'elementor-waypoints',
            'share-link'
        )
    );
	/**
	 * @var Main|null
	 */
	private static $singleton;
	/**
	 * @return null|Main
	 */
	public static function instance()
    {
		if ( self::$singleton === null ) {
			self::$singleton = new self();
		}
		return self::$singleton;
	}
	/**
	 * Parser constructor.
	 */
	public function __construct()
    {
		$this->skipAssets['styles'] = array_merge(
            array(
                'admin-bar',
                // The top admin bar
                'yoast-seo-adminbar',
                // Yoast "WordPress SEO" plugin
                'autoptimize-toolbar',
                'query-monitor',
                'wp-fastest-cache-toolbar',
                // WP Fastest Cache plugin toolbar CSS
                'litespeed-cache',
                // LiteSpeed toolbar
                'siteground-optimizer-combined-styles-header'
                // Combine CSS in SG Optimiser (irrelevant as it made from the combined handles)
            ),
			// Own Scripts (for admin use only)
			OwnAssets::getOwnAssetsHandles('styles')
        );
		$this->skipAssets['scripts'] = array_merge(
            array(
                'admin-bar',            // The top admin bar
                'autoptimize-toolbar',
                'query-monitor',
                'wpfc-toolbar'          // WP Fastest Cache plugin toolbar JS
		    ),
			// Own Scripts (for admin use only)
			OwnAssets::getOwnAssetsHandles('scripts')
        );
	    // Filter before triggering the actual unloading through "wp_deregister_script", "wp_dequeue_script", "wp_deregister_style", "wp_dequeue_style"
	    $this->fallbacks();
		$this->isAjaxCall      = ( ! empty( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) === 'xmlhttprequest' );
		$this->isGetAssetsCall = isset( $_REQUEST[ WPACU_LOAD_ASSETS_REQ_KEY ] ) && $_REQUEST[ WPACU_LOAD_ASSETS_REQ_KEY ];
		if ( $this->isGetAssetsCall ) {
			$currentTheme = strtolower(wp_get_theme());
			$noRocketInit = true;
			if (strpos($currentTheme, 'uncode') !== false) {
				$noRocketInit = false; // make exception for the "Uncode" Theme as it doesn't check if the get_rocket_option() function exists
			}
			if ($noRocketInit) {
			    add_filter('rocket_cache_reject_uri', function($urls) {
				    $urls[] = '/?wpassetcleanup_load=1';
			        return $urls;
                });
			    }
			// Do not output Query Monitor's information as it's irrelevant in this context
			if ( class_exists( '\QueryMonitor' ) && class_exists( '\QM_Plugin' ) ) {
				add_filter( 'user_has_cap', static function( $user_caps ) {
					$user_caps['view_query_monitor'] = false;
					return $user_caps;
				}, 10, 1 );
			}
			add_filter( 'style_loader_tag', static function( $styleTag, $tagHandle ) {
				// This is used to determine if the LINK is enqueued later on
				// If the handle name is not showing up, then the LINK stylesheet has been hardcoded (not enqueued the WordPress way)
				return str_replace( ' '
		 $obj) {
                if (! isset($obj->handle)) {
                    unset($data['all']['styles']['']);
                    continue;
                }
	            // From WordPress directories (false by default, unless it was set to true before: in Sorting.php for instance)
	            if (! isset($data['all']['styles'][$key]->wp)) {
		            $data['all']['styles'][$key]->wp = false;
	            }
	            if ($alterPosition) {
	                if ( in_array( $obj->handle, $this->assetsInFooter['styles'] ) ) {
		                $data['all']['styles'][ $key ]->position = 'body';
	                } else {
		                $data['all']['styles'][ $key ]->position = 'head';
	                }
                }
                if (isset($data['all']['styles'][$key], $obj->src) && $obj->src) {
	                $localSrc = Misc::getLocalSrc($obj->src);
	                if (! empty($localSrc)) {
		                $data['all']['styles'][$key]->baseUrl = $localSrc['base_url'];
		                if (Sorting::matchesWpCoreCriteria($obj, 'styles')) {
                            $data['all']['styles'][ $key ]->wp = true;
                            $data['core_styles_loaded']        = true;
                        }
	                }
                    // Determine source href (starting with '/' but not starting with '//')
                    if (strpos($obj->src, '/') === 0 && strpos($obj->src, '//') !== 0) {
                        $obj->srcHref = $siteUrl . $obj->src;
                    } else {
                        $obj->srcHref = $obj->src;
                    }
	                $data['all']['styles'][$key]->size    = apply_filters('wpacu_get_asset_file_size', $data['all']['styles'][$key], 'for_print');
	                $data['all']['styles'][$key]->sizeRaw = apply_filters('wpacu_get_asset_file_size', $data['all']['styles'][$key], 'raw');
                }
            }
        }
        if (! empty($data['all']['scripts'])) {
            $data['core_scripts_loaded'] = false;
            foreach ($data['all']['scripts'] as $key => $obj) {
                if (! isset($obj->handle)) {
                    unset($data['all']['scripts']['']);
                    continue;
                }
	            // From WordPress directories (false by default, unless it was set to true before: in Sorting.php for instance)
	            if (! isset($data['all']['scripts'][$key]->wp)) {
		            $data['all']['scripts'][$key]->wp = false;
	            }
	            if ($alterPosition) {
		            $initialScriptPos = ObjectCache::wpacu_cache_get( $obj->handle, 'wpacu_scripts_initial_positions' );
		            if ( $initialScriptPos === 'body' || in_array( $obj->handle, $this->assetsInFooter['scripts'] ) ) {
			            $data['all']['scripts'][ $key ]->position = 'body';
		            } else {
			            $data['all']['scripts'][ $key ]->position = 'head';
		            }
	            }
                if (isset($data['all']['scripts'][$key])) {
                    if (isset($obj->src) && $obj->src) {
	                    $localSrc = Misc::getLocalSrc($obj->src);
	                    if (! empty($localSrc)) {
		                    $data['all']['scripts'][$key]->baseUrl = $localSrc['base_url'];
                            if (Sorting::matchesWpCoreCriteria($obj, 'scripts')) {
	                            $data['all']['scripts'][ $key ]->wp = true;
	                            $data['core_scripts_loaded']        = true;
                            }
                        }
                        // Determine source href
                        if (substr($obj->src, 0, 1) === '/' && substr($obj->src, 0, 2) !== '//') {
                            $obj->srcHref = $siteUrl . $obj->src;
                        } else {
                            $obj->srcHref = $obj->src;
                        }
                    }
                    if (in_array($obj->handle,  array('jquery', 'jquery-core', 'jquery-migrate'))) {
                        $data['all']['scripts'][$key]->wp = true;
                        $data['core_scripts_loaded']      = true;
                    }
	                $data['all']['scripts'][$key]->size    = apply_filters('wpacu_get_asset_file_size', $data['all']['scripts'][$key], 'for_print');
	                $data['all']['scripts'][$key]->sizeRaw = apply_filters('wpacu_get_asset_file_size', $data['all']['scripts'][$key], 'raw');
                }
            }
        }
        return $data;
    }
    /**
     * This method retrieves only the assets that are unloaded per page
     * Including 404, date and search pages (they are considered as ONE page with the same rules for any URL variation)
     *
     * @param int $postId
     * @param bool $returnAsArray
     *
     * @return string|array (The returned value must be a JSON one)
     */
    public function getAssetsUnloadedPageLevel($postId = 0, $returnAsArray = false)
    {
        $defaultEmptyArrayValue = array( 'styles' => array(), 'scripts' => array() );
        // Post Type (Overwrites 'front' - home page - if we are in a singular post)
        if ($postId == 0) {
            $postId = (int)$this->getCurrentPostId();
        }
        $isInAdminPageViaAjax = (is_admin() && defined('DOING_AJAX') && DOING_AJAX);
	    $assetsRemovedPageLevel = wp_json_encode( $defaultEmptyArrayValue );
        // For Home Page (latest blog posts)
        if ( $postId < 1 && ( $isInAdminPageViaAjax || Misc::isHomePage() ) ) {
            $assetsRemovedPageLevel = get_option( WPACU_PLUGIN_ID . '_front_page_no_load' );
        } elseif ( $postId > 0 ) { // Singular Page
            $assetsRemovedPageLevel = get_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_no_load', true );
        }
        @json_decode( $assetsRemovedPageLevel );
        if ( ! ( Misc::jsonLastError() === JSON_ERROR_NONE ) || empty( $assetsRemovedPageLevel ) || $assetsRemovedPageLevel === '[]' ) {
            // Reset value to a JSON formatted one
	        $assetsRemovedPageLevel = wp_json_encode( $defaultEmptyArrayValue );
        }
        $assetsRemovedDecoded = json_decode( $assetsRemovedPageLevel, ARRAY_A );
        if (! isset($assetsRemovedDecoded['styles'])) {
            $assetsRemovedDecoded['styles'] = array();
        }
        if (! isset($assetsRemovedDecoded['scripts'])) {
            $assetsRemovedDecoded['scripts'] = array();
        }
        /* [START] Unload CSS/JS on page request for debugging purposes */
        $assetsUnloadedOnTheFly = $defaultEmptyArrayValue;
        if ( Misc::getVar( 'get', 'wpacu_unload_css' ) ) {
            $cssOnTheFlyList = $this->unloadAssetOnTheFly( 'css' );
            if ( ! empty( $cssOnTheFlyList ) ) {
                foreach ( $cssOnTheFlyList as $cssHandle ) {
                    if ( ! in_array( $cssHandle, $assetsRemovedDecoded['styles'] ) ) {
                        $assetsRemovedDecoded['styles'][] = $assetsUnloadedOnTheFly['styles'][] = $cssHandle;
                    }
                }
            }
        }
        if ( Misc::getVar( 'get', 'wpacu_unload_js' ) ) {
            $jsOnTheFlyList = $this->unloadAssetOnTheFly( 'js' );
            if ( ! empty( $jsOnTheFlyList ) ) {
                foreach ( $jsOnTheFlyList as $jsHandle ) {
                    if ( ! in_array( $jsHandle, $assetsRemovedDecoded['scripts'] ) ) {
                        $assetsRemovedDecoded['scripts'][] = $assetsUnloadedOnTheFly['scripts'][] = $jsHandle;
                    }
                }
            }
        }
        ObjectCache::wpacu_cache_add( 'wpacu_assets_unloaded_list_page_request', $assetsUnloadedOnTheFly );
        /* [END] Unload CSS/JS on page request for debugging purposes */
	    $assetsRemovedPageLevel = wp_json_encode( $assetsRemovedDecoded );
        if ($returnAsArray) {
	        $assetsRemovedPageLevel = (array)@json_decode($assetsRemovedPageLevel);
	        // Make sure there are no objects in the array to avoid any PHP errors later on in PHP 8+
	        foreach ( array( 'styles', 'scripts' ) as $assetType ) {
		        if ( isset( $assetsRemovedPageLevel[ $assetType ] ) ) {
			        $assetsRemovedPageLevel[ $assetType ] = (array)$assetsRemovedPageLevel[ $assetType ];
		        }
	        }
        }
        // Hmm, perhaps one of the filters was incorrectly used and returned an array instead of a JSON format; autocorrect this to avoid PHP errors
        if (! $returnAsArray && is_array($assetsRemovedPageLevel)) {
            return wp_json_encode( $defaultEmptyArrayValue );
        }
	    return $assetsRemovedPageLevel;
    }
	/**
	 * @param $allAssets
	 *
	 * @return array
	 */
	public function getAllDeps($allAssets)
	{
		$allDepsParentToChild = $allDepsChildToParent = array('styles' => array(), 'scripts' => array());
		foreach (array('styles', 'scripts') as $assetType) {
			if ( ! (isset($allAssets[$assetType]) && ! empty($allAssets[$assetType])) ) {
				continue;
			}
			foreach ($allAssets[$assetType] as $assetObj) {
				if (isset($assetObj->deps) && ! empty($assetObj->deps)) {
					foreach ($assetObj->deps as $dep) {
						$allDepsParentToChild[$assetType][$dep][] = $assetObj->handle;
						$allDepsChildToParent[$assetType][$assetObj->handle][] = $dep;
					}
				}
			}
		}
		return array(
            'parent_to_child'      => $allDepsParentToChild,
            'child_to_parent'      => $allDepsChildToParent
        );
	}
	/**
	 * @param $obj
	 * @param $format | 'for_print': Calculates the format in KB / MB  - 'raw': The actual size in bytes
	 * @return string
	 */
	public function getAssetFileSize($obj, $format = 'for_print')
	{
		if (isset($obj->src) && $obj->src) {
			$src = $obj->src;
			$siteUrl = site_url();
			// Starts with / but not with //
			// Or starts with ../ (very rare cases)
			$isRelInternalPath = (strpos($src, '/') === 0 && strpos($src, '//') !== 0) || (strpos($src, '../') === 0);
			// Source starts with '//' - check if the file exists
			if (strpos($obj->src, '//') === 0) {
				list ($urlPrefix) = explode('//', $siteUrl);
				$srcToCheck = $urlPrefix . $obj->src;
				$hostSiteUrl = parse_url($siteUrl, PHP_URL_HOST);
				$hostSrc = parse_url($obj->src, PHP_URL_HOST);
				$siteUrlAltered = str_replace(array($hostSiteUrl, $hostSrc), '{site_host}', $siteUrl);
				$srcAltered = str_replace(array($hostSiteUrl, $hostSrc), '{site_host}', $srcToCheck);
				$srcMaybeRelPath = str_replace($siteUrlAltered, '', $srcAltered);
				$possibleStrips = array('?ver', '?cache=');
				foreach ($possibleStrips as $possibleStrip) {
					if ( strpos( $srcMaybeRelPath, $possibleStrip ) !== false ) {
						list ( $srcMaybeRelPath ) = explode( $possibleStrip, $srcMaybeRelPath );
					}
				}
				if (is_file(Misc::getWpRootDirPath() . $srcMaybeRelPath)) {
					$fileSize = filesize(Misc::getWpRootDirPath() . $srcMaybeRelPath);
					if ($format === 'raw') {
						return (int)$fileSize;
					}
					return Misc::formatBytes($fileSize);
				}
			}
			// e.g. /?scss=1 (Simple Custom CSS Plugin)
			if (str_replace($siteUrl, '', $src) === '/?sccss=1') {
				$customCss = DynamicLoadedAssets::getSimpleCustomCss();
				$sizeInBytes = mb_strlen($customCss);
				if ($format === 'raw') {
					return $sizeInBytes;
				}
				return Misc::formatBytes($sizeInBytes);
			}
			// External file? Use a different approach
			// Return an HTML code that will be parsed via AJAX through JavaScript
			$isExternalFile = (! $isRelInternalPath &&
			                   (! (isset($obj->wp) && $obj->wp === 1))
			                   && strpos($src, $siteUrl) !== 0);
			// e.g. /?scss=1 (Simple Custom CSS Plugin) From External Domain
			// /?custom-css (JetPack Custom CSS)
			$isLoadedOnTheFly = (strpos($src, '?sccss=1') !== false)
			                    || (strpos($src, '?custom-css') !== false);
			if ($isExternalFile || $isLoadedOnTheFly) {
				return '🔗 Get File Size'.
				       '.') ';
			}
			$forAssetType = $pathToFile = false;
            if ( stripos( $src, '.css' ) !== false ) {
                $forAssetType = 'css';
            } elseif ( stripos( $src, '.js' ) !== false ) {
                $forAssetType = 'js';
            }
            if ($forAssetType) {
	            $pathToFile = OptimizeCommon::getLocalAssetPath( $src, $forAssetType );
            }
			if ( ! is_file($pathToFile) ) { // Fallback, old code...
				// Local file? Core or from a plugin / theme?
				if ( strpos( $obj->src, $siteUrl ) !== false ) {
					// Local Plugin / Theme File
					// Could be a Staging site that is having the Live URL in the General Settings
					$src = ltrim( str_replace( $siteUrl, '', $obj->src ), '/' );
				} elseif ( ( isset( $obj->wp ) && $obj->wp === 1 ) || $isRelInternalPath ) {
					// Local WordPress Core File
					$src = ltrim( $obj->src, '/' );
				}
				$srcAlt = $src;
				if ( strpos( $src, '../' ) === 0 ) {
					$srcAlt = str_replace( '../', '', $srcAlt );
				}
				$pathToFile = Misc::getWpRootDirPath() . $srcAlt;
				if ( strpos( $pathToFile, '?ver' ) !== false ) {
					list( $pathToFile ) = explode( '?ver', $pathToFile );
				}
				// It can happen that the CSS/JS has extra parameters (rare cases)
				foreach ( array( '.css?', '.js?' ) as $needlePart ) {
					if ( strpos( $pathToFile, $needlePart ) !== false ) {
						list( $pathToFile ) = explode( '?', $pathToFile );
					}
				}
			}
			if (is_file($pathToFile)) {
				$sizeInBytes = filesize($pathToFile);
				if ($format === 'raw') {
					return (int)$sizeInBytes;
				}
				return Misc::formatBytes($sizeInBytes);
			}
			return 'Error: Could not read '.$pathToFile.'';
		}
		if ($obj->handle === 'jquery' && isset($obj->src) && ! $obj->src) {
			return '"jquery-core" size';
		}
		// External or nothing to be shown (perhaps due to an error)
		return '';
	}
	/**
	 * Source: https://stackoverflow.com/questions/2602612/remote-file-size-without-downloading-file
	 */
	public function ajaxGetExternalFileSize()
	{
		// Check nonce
		if ( ! isset( $_POST['wpacu_nonce'] ) || ! wp_verify_nonce( $_POST['wpacu_nonce'], 'wpacu_ajax_check_remote_file_size_nonce' ) ) {
			echo 'Error: The security nonce is not valid.';
			exit();
		}
		// Check privileges
		if (! Menu::userCanManageAssets()) {
			echo 'Error: Not enough privileges to perform this action.';
			exit();
		}
		// Assume failure.
		$result = -1;
		$remoteFile = Misc::getVar('post', 'wpacu_remote_file', false);
		if (! $remoteFile) {
			echo 'N/A (external file)';
			exit;
		}
		// If it starts with //
		if (strpos($remoteFile, '//') === 0) {
			$remoteFile = 'http:'.$remoteFile;
		}
		// Check if the URL is valid
		if (! filter_var($remoteFile, FILTER_VALIDATE_URL)) {
			echo 'The asset\'s URL - '.$remoteFile.' - is not valid.';
			exit();
		}
		$curl = curl_init($remoteFile);
		// Issue a HEAD request and follow any redirects.
		curl_setopt($curl, CURLOPT_NOBODY, true);
		curl_setopt($curl, CURLOPT_HEADER, true);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
		$data = curl_exec($curl);
		curl_close($curl);
		$content_length = $status = 'unknown';
		if ($data) {
			if (preg_match( '/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches ) ) {
				$status = (int)$matches[1];
			}
			if ( preg_match( '/Content-Length: (\d+)/', $data, $matches ) ) {
				$content_length = (int)$matches[1];
			}
			// http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
			if ( $status === 200 || ($status > 300 && $status <= 308) ) {
				$result = $content_length;
			}
		}
		if ($content_length === 'unknown') {
			// One more try
			$response     = wp_remote_get($remoteFile);
			$responseCode = wp_remote_retrieve_response_code($response);
			if ($responseCode === 200) {
				$result = mb_strlen(wp_remote_retrieve_body($response));
			}
		}
		echo Misc::formatBytes($result);
		if (stripos($remoteFile, '//fonts.googleapis.com/') !== false) {
			// Google Font APIS CDN
			echo ' + the sizes of the loaded "Google Font" files (see "url" from @font-face within the Source file)';
		} elseif (stripos($remoteFile, '/font-awesome.css') || stripos($remoteFile, '/font-awesome.min.css')) {
			// FontAwesome CDN
			echo ' + the sizes of the loaded "FontAwesome" font files (see "url" from @font-face within the Source file)';
		}
		exit();
	}
    /**
     * @return bool
     */
    public static function isSingularPage()
    {
        return (self::$vars['is_woo_shop_page'] || is_singular() || Misc::isBlogPage());
    }
    /**
     * @return int|mixed|string
     */
    public function getCurrentPostId()
    {
        if ($this->currentPostId > 0) {
            return $this->currentPostId;
        }
        if (Misc::isElementorMaintenanceModeOnForCurrentAdmin() && defined('WPACU_IS_ELEMENTOR_MAINTENANCE_MODE_TEMPLATE_ID')) {
            $this->currentPostId = WPACU_IS_ELEMENTOR_MAINTENANCE_MODE_TEMPLATE_ID;
            return $this->currentPostId;
        }
        // Are we on the `Shop` page from WooCommerce?
        // Only check option if function `is_shop` exists
        $wooCommerceShopPageId = function_exists('is_shop') ? get_option('woocommerce_shop_page_id') : 0;
        // Check if we are on the WooCommerce Shop Page
        // Do not mix the WooCommerce Search Page with the Shop Page
        if (function_exists('is_shop') && is_shop()) {
            $this->currentPostId = $wooCommerceShopPageId;
            if ($this->currentPostId > 0) {
                self::$vars['is_woo_shop_page'] = true;
            }
        } else {
            if ($wooCommerceShopPageId > 0 && Misc::isHomePage() && strpos(get_site_url(), '://') !== false) {
                list($siteUrlAfterProtocol) = explode('://', get_site_url());
                $currentPageUrlAfterProtocol = parse_url(site_url(), PHP_URL_HOST) . $_SERVER['REQUEST_URI'];
                if ($siteUrlAfterProtocol != $currentPageUrlAfterProtocol && (strpos($siteUrlAfterProtocol, '/shop') !== false)) {
	                self::$vars['woo_url_not_match'] = true;
                }
            }
        }
	    // Blog Home Page (aka: Posts page) is not a singular page, it's checked separately
        if (Misc::isBlogPage()) {
        	$this->currentPostId = get_option('page_for_posts');
        }
        // It has to be a single page (no "Posts page")
        if (($this->currentPostId < 1) && is_singular()) {
            global $post;
            $this->currentPostId = isset($post->ID) ? $post->ID : 0;
        }
	    // [wpacu_lite]
        // Undetectable? The page is not a singular one nor the home page
        // It's likely an archive, category page (WooCommerce), 404 page manageable in the Pro version etc.
        if (! $this->currentPostId && ! Misc::isHomePage()) {
            $this->isUpdateable = false;
        }
	    // [/wpacu_lite]
        return $this->currentPostId;
    }
    /**
     * @return array|null|\WP_Post
     */
    public function getCurrentPost()
    {
        // Already set? Return it
        if (! empty($this->currentPost)) {
            return $this->currentPost;
        }
        // Not set? Create and return it
        if (! $this->currentPost && $this->getCurrentPostId() > 0) {
            $this->currentPost = get_post($this->getCurrentPostId());
            return $this->currentPost;
        }
        // Empty
        return $this->currentPost;
    }
	/**
	 * Get all contracted rows
	 *
	 * @return array
	 */
	public static function getHandleRowStatus()
	{
		$handleRowStatus = array('styles' => array(), 'scripts' => array());
		$handleRowStatusListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
		$globalKey = 'handle_row_contracted';
		if ($handleRowStatusListJson) {
			$handleRowStatusList = @json_decode($handleRowStatusListJson, true);
			// Issues with decoding the JSON file? Return an empty list
			if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
				return $handleRowStatus;
			}
			// Are new positions set for styles and scripts?
			foreach (array('styles', 'scripts') as $assetKey) {
				if ( isset( $handleRowStatusList[$assetKey][$globalKey] ) && ! empty( $handleRowStatusList[$assetKey][$globalKey] ) ) {
					$handleRowStatus[$assetKey] = $handleRowStatusList[$assetKey][$globalKey];
				}
			}
		}
		return $handleRowStatus;
	}
	/**
	 * @param $postType
	 *
	 * @return array
	 */
	public static function getAllSetTaxonomies($postType)
	{
		if ( ! $postType ) {
			return array();
		}
		$postTaxonomies = get_object_taxonomies($postType);
		if ($postType === 'post') {
			$postFormatKey = array_search('post_format', $postTaxonomies);
			unset($postTaxonomies[$postFormatKey]);
		}
		if (empty($postTaxonomies)) {
			// There are no taxonomies associate with the $postType or $postType is not valid
			return array();
		}
		$allPostTypeTaxonomyTerms = get_terms( array(
			'taxonomy' => $postTaxonomies,
			'hide_empty' => true,
		) );
		$finalList = array();
		foreach ($allPostTypeTaxonomyTerms as $obj) {
			$taxonomyObj = get_taxonomy($obj->taxonomy);
			if ( ! $taxonomyObj->show_ui ) {
				continue;
			}
			$finalList[$taxonomyObj->label][] = (array)$obj;
		}
        if ( ! empty($finalList) ) {
	        foreach ( array_keys( $finalList ) as $taxonomyLabel ) {
		        usort( $finalList[ $taxonomyLabel ], static function( $a, $b ) {
			        return strcasecmp( $a['name'], $b['name'] );
		        } );
	        }
	        ksort($finalList);
        }
		return $finalList;
	}
	/**
	 * @param $data
	 *
	 * @return mixed
	 */
	public function setPageTemplate($data)
    {
    	global $template;
	    $getPageTpl = get_post_meta($this->getCurrentPostId(), '_wp_page_template', true);
	    // Could be a custom post type with no template set
	    if (! $getPageTpl) {
		    $getPageTpl = get_page_template();
		    if (in_array(basename($getPageTpl), array('single.php', 'page.php'))) {
			    $getPageTpl = 'default';
		    }
	    }
	    if (! $getPageTpl) {
	    	return $data;
	    }
	    $data['page_template'] = $getPageTpl;
	    $data['all_page_templates'] = wp_get_theme()->get_page_templates();
	    // Is the default template shown? Most of the time it is!
	    if ($data['page_template'] === 'default') {
	    	$pageTpl = (isset($template) && $template) ? $template : get_page_template();
		    $data['page_template'] = basename( $pageTpl );
		    $data['all_page_templates'][ $data['page_template'] ] = 'Default Template';
	    }
	    if (isset($template) && $template && defined('ABSPATH')) {
	    	$data['page_template_path'] = str_replace(
			    Misc::getWpRootDirPath(),
			    '',
			    '/'.$template
		    );
	    }
	    return $data;
    }
	/**
	 * @return bool
	 */
	public static function isWpDefaultSearchPage()
	{
		// It will not interfere with the WooCommerce search page
		// which is considered to be the "Shop" page that has its own unload rules
		return (is_search() && (! (function_exists('is_shop') && is_shop())));
	}
	/**
	 * @param $existingListJson
	 * @param $existingListEmpty
	 *
	 * @return array
	 */
	public function existingList($existingListJson, $existingListEmpty)
	{
		$validJson = $notEmpty = true;
		if (! $existingListJson) {
			$existingList = $existingListEmpty;
			$notEmpty = false;
		} else {
			$existingList = json_decode($existingListJson, true);
			if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
				$validJson = false;
				$existingList = $existingListEmpty;
			}
		}
		return array(
			'list'       => $existingList,
			'valid_json' => $validJson,
			'not_empty'  => $notEmpty
		);
	}
	/**
	 * Situations when the assets will not be prevented from loading
	 * e.g. test mode and a visitor accessing the page, an AJAX request from the Dashboard to print all the assets
     *
	 * @param array $ignoreList
	 *
	 * @return bool
	 */
	public function preventAssetsSettings($ignoreList = array())
	{
		// This request specifically asks for all the assets to be loaded in order to print them in the assets management list
		// This is for the AJAX requests within the Dashboard, thus the admin needs to see all the assets,
		// including ones marked for unload, in case he/she decides to change their rules
		if ($this->isGetAssetsCall && ! in_array('assets_call', $ignoreList)) {
			return true;
		}
		// Is test mode enabled? Unload assets ONLY for the admin
		if (self::isTestModeActive()) {
			return true; // visitors (non-logged in) will view the pages with all the assets loaded
		}
		$isSingularPage = defined('WPACU_CURRENT_PAGE_ID') && WPACU_CURRENT_PAGE_ID > 0 && is_singular();
		if ($isSingularPage || Misc::isHomePage()) {
			if ($isSingularPage) {
				$pageOptions = MetaBoxes::getPageOptions( WPACU_CURRENT_PAGE_ID ); // Singular page
			} else {
				$pageOptions = MetaBoxes::getPageOptions(0, 'front_page'); // Home page
			}
			if (isset($pageOptions['no_assets_settings']) && $pageOptions['no_assets_settings']) {
				return true;
			}
		}
		return false;
	}
	/**
	 * @param array $settings
	 *
	 * @return bool
	 */
	public static function isTestModeActive($settings = array())
    {
        if (defined('WPACU_IS_TEST_MODE_ACTIVE')) {
            return WPACU_IS_TEST_MODE_ACTIVE;
        }
        if (! $settings) {
            $settings = self::instance()->settings;
        }
        $wpacuIsTestModeActive = isset($settings['test_mode']) && $settings['test_mode'] && ! Menu::userCanManageAssets();
        define('WPACU_IS_TEST_MODE_ACTIVE', $wpacuIsTestModeActive);
        return $wpacuIsTestModeActive;
    }
	/**
	 * @return bool
	 */
	public static function currentUserCanViewAssetsList()
    {
	    if ( Main::instance()->settings['allow_manage_assets_to'] === 'chosen' && ! empty(Main::instance()->settings['allow_manage_assets_to_list']) ) {
		    $wpacuCurrentUserId = get_current_user_id();
		    if ( ! in_array( $wpacuCurrentUserId, Main::instance()->settings['allow_manage_assets_to_list'] ) ) {
			    return false; // the current logged-in admin is not in the list of "Allow managing assets to:"
		    }
	    }
	    return true;
    }
	/**
	 * @return bool
	 */
	public function frontendShow()
    {
        // The option is disabled
	    if (! $this->settings['frontend_show']) {
		    return false;
	    }
	    // The asset list is hidden via query string: /?wpacu_no_frontend_show
	    if (isset($_REQUEST['wpacu_no_frontend_show'])) {
	        return false;
        }
	    // Page loaded via Yellow Pencil Editor within an iframe? Do not show it as it's irrelevant there
        if (isset($_GET['yellow_pencil_frame'], $_GET['yp_page_type'])) {
            return false;
        }
	    // The option is enabled, but there are show exceptions, check if the list should be hidden
        if ($this->settings['frontend_show_exceptions']) {
	        $frontendShowExceptions = trim( $this->settings['frontend_show_exceptions'] );
	        // We want to make sure the RegEx rules will be working fine if certain characters (e.g. Thai ones) are used
	        $requestUriAsItIs = rawurldecode($_SERVER['REQUEST_URI']);
	        if ( strpos( $frontendShowExceptions, "\n" ) !== false ) {
		        foreach ( explode( "\n", $frontendShowExceptions ) as $frontendShowException ) {
			        $frontendShowException = trim($frontendShowException);
			        if ( strpos( $requestUriAsItIs, $frontendShowException ) !== false ) {
				        return false;
			        }
		        }
	        } elseif ( strpos( $requestUriAsItIs, $frontendShowExceptions ) !== false ) {
                return false;
	        }
        }
        // Allows managing assets to chosen admins and the user is not in the list
        if ( ! self::currentUserCanViewAssetsList() ) {
            return false;
        }
        return true;
    }
	/**
	 * Make administrator more aware if "TEST MODE" is enabled or not
	 */
	public function wpacuHtmlNoticeForAdmin()
	{
		add_action('wp_footer', static function() {
			if ((WPACU_GET_LOADED_ASSETS_ACTION === true) || (! apply_filters('wpacu_show_admin_console_notice', true)) || Plugin::preventAnyFrontendOptimization()) {
				return;
			}
			if ( ! (Menu::userCanManageAssets() && ! is_admin())) {
				return;
			}
			if (Main::instance()->settings['test_mode']) {
				$consoleMessage = sprintf(esc_html__('%s: "TEST MODE" ENABLED (any settings or unloads will be visible ONLY to you, the logged-in administrator)', 'wp-asset-clean-up'), WPACU_PLUGIN_TITLE);
				$testModeNotice = esc_html__('"Test Mode" is ENABLED. Any settings or unloads will be visible ONLY to you, the logged-in administrator.', 'wp-asset-clean-up');
			} else {
				$consoleMessage = sprintf(esc_html__('%s: "LIVE MODE" (test mode is not enabled, thus, all the plugin changes are visible for everyone: you, the logged-in administrator and the regular visitors)', 'wp-asset-clean-up'), WPACU_PLUGIN_TITLE);
				$testModeNotice = esc_html__('The website is in LIVE MODE as "Test Mode" is not enabled. All the plugin changes are visible for everyone: logged-in administrators and regular visitors.', 'wp-asset-clean-up');
			}
			?>
';
			}
			$forAssetType = $pathToFile = false;
            if ( stripos( $src, '.css' ) !== false ) {
                $forAssetType = 'css';
            } elseif ( stripos( $src, '.js' ) !== false ) {
                $forAssetType = 'js';
            }
            if ($forAssetType) {
	            $pathToFile = OptimizeCommon::getLocalAssetPath( $src, $forAssetType );
            }
			if ( ! is_file($pathToFile) ) { // Fallback, old code...
				// Local file? Core or from a plugin / theme?
				if ( strpos( $obj->src, $siteUrl ) !== false ) {
					// Local Plugin / Theme File
					// Could be a Staging site that is having the Live URL in the General Settings
					$src = ltrim( str_replace( $siteUrl, '', $obj->src ), '/' );
				} elseif ( ( isset( $obj->wp ) && $obj->wp === 1 ) || $isRelInternalPath ) {
					// Local WordPress Core File
					$src = ltrim( $obj->src, '/' );
				}
				$srcAlt = $src;
				if ( strpos( $src, '../' ) === 0 ) {
					$srcAlt = str_replace( '../', '', $srcAlt );
				}
				$pathToFile = Misc::getWpRootDirPath() . $srcAlt;
				if ( strpos( $pathToFile, '?ver' ) !== false ) {
					list( $pathToFile ) = explode( '?ver', $pathToFile );
				}
				// It can happen that the CSS/JS has extra parameters (rare cases)
				foreach ( array( '.css?', '.js?' ) as $needlePart ) {
					if ( strpos( $pathToFile, $needlePart ) !== false ) {
						list( $pathToFile ) = explode( '?', $pathToFile );
					}
				}
			}
			if (is_file($pathToFile)) {
				$sizeInBytes = filesize($pathToFile);
				if ($format === 'raw') {
					return (int)$sizeInBytes;
				}
				return Misc::formatBytes($sizeInBytes);
			}
			return 'Error: Could not read '.$pathToFile.'';
		}
		if ($obj->handle === 'jquery' && isset($obj->src) && ! $obj->src) {
			return '"jquery-core" size';
		}
		// External or nothing to be shown (perhaps due to an error)
		return '';
	}
	/**
	 * Source: https://stackoverflow.com/questions/2602612/remote-file-size-without-downloading-file
	 */
	public function ajaxGetExternalFileSize()
	{
		// Check nonce
		if ( ! isset( $_POST['wpacu_nonce'] ) || ! wp_verify_nonce( $_POST['wpacu_nonce'], 'wpacu_ajax_check_remote_file_size_nonce' ) ) {
			echo 'Error: The security nonce is not valid.';
			exit();
		}
		// Check privileges
		if (! Menu::userCanManageAssets()) {
			echo 'Error: Not enough privileges to perform this action.';
			exit();
		}
		// Assume failure.
		$result = -1;
		$remoteFile = Misc::getVar('post', 'wpacu_remote_file', false);
		if (! $remoteFile) {
			echo 'N/A (external file)';
			exit;
		}
		// If it starts with //
		if (strpos($remoteFile, '//') === 0) {
			$remoteFile = 'http:'.$remoteFile;
		}
		// Check if the URL is valid
		if (! filter_var($remoteFile, FILTER_VALIDATE_URL)) {
			echo 'The asset\'s URL - '.$remoteFile.' - is not valid.';
			exit();
		}
		$curl = curl_init($remoteFile);
		// Issue a HEAD request and follow any redirects.
		curl_setopt($curl, CURLOPT_NOBODY, true);
		curl_setopt($curl, CURLOPT_HEADER, true);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
		$data = curl_exec($curl);
		curl_close($curl);
		$content_length = $status = 'unknown';
		if ($data) {
			if (preg_match( '/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches ) ) {
				$status = (int)$matches[1];
			}
			if ( preg_match( '/Content-Length: (\d+)/', $data, $matches ) ) {
				$content_length = (int)$matches[1];
			}
			// http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
			if ( $status === 200 || ($status > 300 && $status <= 308) ) {
				$result = $content_length;
			}
		}
		if ($content_length === 'unknown') {
			// One more try
			$response     = wp_remote_get($remoteFile);
			$responseCode = wp_remote_retrieve_response_code($response);
			if ($responseCode === 200) {
				$result = mb_strlen(wp_remote_retrieve_body($response));
			}
		}
		echo Misc::formatBytes($result);
		if (stripos($remoteFile, '//fonts.googleapis.com/') !== false) {
			// Google Font APIS CDN
			echo ' + the sizes of the loaded "Google Font" files (see "url" from @font-face within the Source file)';
		} elseif (stripos($remoteFile, '/font-awesome.css') || stripos($remoteFile, '/font-awesome.min.css')) {
			// FontAwesome CDN
			echo ' + the sizes of the loaded "FontAwesome" font files (see "url" from @font-face within the Source file)';
		}
		exit();
	}
    /**
     * @return bool
     */
    public static function isSingularPage()
    {
        return (self::$vars['is_woo_shop_page'] || is_singular() || Misc::isBlogPage());
    }
    /**
     * @return int|mixed|string
     */
    public function getCurrentPostId()
    {
        if ($this->currentPostId > 0) {
            return $this->currentPostId;
        }
        if (Misc::isElementorMaintenanceModeOnForCurrentAdmin() && defined('WPACU_IS_ELEMENTOR_MAINTENANCE_MODE_TEMPLATE_ID')) {
            $this->currentPostId = WPACU_IS_ELEMENTOR_MAINTENANCE_MODE_TEMPLATE_ID;
            return $this->currentPostId;
        }
        // Are we on the `Shop` page from WooCommerce?
        // Only check option if function `is_shop` exists
        $wooCommerceShopPageId = function_exists('is_shop') ? get_option('woocommerce_shop_page_id') : 0;
        // Check if we are on the WooCommerce Shop Page
        // Do not mix the WooCommerce Search Page with the Shop Page
        if (function_exists('is_shop') && is_shop()) {
            $this->currentPostId = $wooCommerceShopPageId;
            if ($this->currentPostId > 0) {
                self::$vars['is_woo_shop_page'] = true;
            }
        } else {
            if ($wooCommerceShopPageId > 0 && Misc::isHomePage() && strpos(get_site_url(), '://') !== false) {
                list($siteUrlAfterProtocol) = explode('://', get_site_url());
                $currentPageUrlAfterProtocol = parse_url(site_url(), PHP_URL_HOST) . $_SERVER['REQUEST_URI'];
                if ($siteUrlAfterProtocol != $currentPageUrlAfterProtocol && (strpos($siteUrlAfterProtocol, '/shop') !== false)) {
	                self::$vars['woo_url_not_match'] = true;
                }
            }
        }
	    // Blog Home Page (aka: Posts page) is not a singular page, it's checked separately
        if (Misc::isBlogPage()) {
        	$this->currentPostId = get_option('page_for_posts');
        }
        // It has to be a single page (no "Posts page")
        if (($this->currentPostId < 1) && is_singular()) {
            global $post;
            $this->currentPostId = isset($post->ID) ? $post->ID : 0;
        }
	    // [wpacu_lite]
        // Undetectable? The page is not a singular one nor the home page
        // It's likely an archive, category page (WooCommerce), 404 page manageable in the Pro version etc.
        if (! $this->currentPostId && ! Misc::isHomePage()) {
            $this->isUpdateable = false;
        }
	    // [/wpacu_lite]
        return $this->currentPostId;
    }
    /**
     * @return array|null|\WP_Post
     */
    public function getCurrentPost()
    {
        // Already set? Return it
        if (! empty($this->currentPost)) {
            return $this->currentPost;
        }
        // Not set? Create and return it
        if (! $this->currentPost && $this->getCurrentPostId() > 0) {
            $this->currentPost = get_post($this->getCurrentPostId());
            return $this->currentPost;
        }
        // Empty
        return $this->currentPost;
    }
	/**
	 * Get all contracted rows
	 *
	 * @return array
	 */
	public static function getHandleRowStatus()
	{
		$handleRowStatus = array('styles' => array(), 'scripts' => array());
		$handleRowStatusListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
		$globalKey = 'handle_row_contracted';
		if ($handleRowStatusListJson) {
			$handleRowStatusList = @json_decode($handleRowStatusListJson, true);
			// Issues with decoding the JSON file? Return an empty list
			if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
				return $handleRowStatus;
			}
			// Are new positions set for styles and scripts?
			foreach (array('styles', 'scripts') as $assetKey) {
				if ( isset( $handleRowStatusList[$assetKey][$globalKey] ) && ! empty( $handleRowStatusList[$assetKey][$globalKey] ) ) {
					$handleRowStatus[$assetKey] = $handleRowStatusList[$assetKey][$globalKey];
				}
			}
		}
		return $handleRowStatus;
	}
	/**
	 * @param $postType
	 *
	 * @return array
	 */
	public static function getAllSetTaxonomies($postType)
	{
		if ( ! $postType ) {
			return array();
		}
		$postTaxonomies = get_object_taxonomies($postType);
		if ($postType === 'post') {
			$postFormatKey = array_search('post_format', $postTaxonomies);
			unset($postTaxonomies[$postFormatKey]);
		}
		if (empty($postTaxonomies)) {
			// There are no taxonomies associate with the $postType or $postType is not valid
			return array();
		}
		$allPostTypeTaxonomyTerms = get_terms( array(
			'taxonomy' => $postTaxonomies,
			'hide_empty' => true,
		) );
		$finalList = array();
		foreach ($allPostTypeTaxonomyTerms as $obj) {
			$taxonomyObj = get_taxonomy($obj->taxonomy);
			if ( ! $taxonomyObj->show_ui ) {
				continue;
			}
			$finalList[$taxonomyObj->label][] = (array)$obj;
		}
        if ( ! empty($finalList) ) {
	        foreach ( array_keys( $finalList ) as $taxonomyLabel ) {
		        usort( $finalList[ $taxonomyLabel ], static function( $a, $b ) {
			        return strcasecmp( $a['name'], $b['name'] );
		        } );
	        }
	        ksort($finalList);
        }
		return $finalList;
	}
	/**
	 * @param $data
	 *
	 * @return mixed
	 */
	public function setPageTemplate($data)
    {
    	global $template;
	    $getPageTpl = get_post_meta($this->getCurrentPostId(), '_wp_page_template', true);
	    // Could be a custom post type with no template set
	    if (! $getPageTpl) {
		    $getPageTpl = get_page_template();
		    if (in_array(basename($getPageTpl), array('single.php', 'page.php'))) {
			    $getPageTpl = 'default';
		    }
	    }
	    if (! $getPageTpl) {
	    	return $data;
	    }
	    $data['page_template'] = $getPageTpl;
	    $data['all_page_templates'] = wp_get_theme()->get_page_templates();
	    // Is the default template shown? Most of the time it is!
	    if ($data['page_template'] === 'default') {
	    	$pageTpl = (isset($template) && $template) ? $template : get_page_template();
		    $data['page_template'] = basename( $pageTpl );
		    $data['all_page_templates'][ $data['page_template'] ] = 'Default Template';
	    }
	    if (isset($template) && $template && defined('ABSPATH')) {
	    	$data['page_template_path'] = str_replace(
			    Misc::getWpRootDirPath(),
			    '',
			    '/'.$template
		    );
	    }
	    return $data;
    }
	/**
	 * @return bool
	 */
	public static function isWpDefaultSearchPage()
	{
		// It will not interfere with the WooCommerce search page
		// which is considered to be the "Shop" page that has its own unload rules
		return (is_search() && (! (function_exists('is_shop') && is_shop())));
	}
	/**
	 * @param $existingListJson
	 * @param $existingListEmpty
	 *
	 * @return array
	 */
	public function existingList($existingListJson, $existingListEmpty)
	{
		$validJson = $notEmpty = true;
		if (! $existingListJson) {
			$existingList = $existingListEmpty;
			$notEmpty = false;
		} else {
			$existingList = json_decode($existingListJson, true);
			if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
				$validJson = false;
				$existingList = $existingListEmpty;
			}
		}
		return array(
			'list'       => $existingList,
			'valid_json' => $validJson,
			'not_empty'  => $notEmpty
		);
	}
	/**
	 * Situations when the assets will not be prevented from loading
	 * e.g. test mode and a visitor accessing the page, an AJAX request from the Dashboard to print all the assets
     *
	 * @param array $ignoreList
	 *
	 * @return bool
	 */
	public function preventAssetsSettings($ignoreList = array())
	{
		// This request specifically asks for all the assets to be loaded in order to print them in the assets management list
		// This is for the AJAX requests within the Dashboard, thus the admin needs to see all the assets,
		// including ones marked for unload, in case he/she decides to change their rules
		if ($this->isGetAssetsCall && ! in_array('assets_call', $ignoreList)) {
			return true;
		}
		// Is test mode enabled? Unload assets ONLY for the admin
		if (self::isTestModeActive()) {
			return true; // visitors (non-logged in) will view the pages with all the assets loaded
		}
		$isSingularPage = defined('WPACU_CURRENT_PAGE_ID') && WPACU_CURRENT_PAGE_ID > 0 && is_singular();
		if ($isSingularPage || Misc::isHomePage()) {
			if ($isSingularPage) {
				$pageOptions = MetaBoxes::getPageOptions( WPACU_CURRENT_PAGE_ID ); // Singular page
			} else {
				$pageOptions = MetaBoxes::getPageOptions(0, 'front_page'); // Home page
			}
			if (isset($pageOptions['no_assets_settings']) && $pageOptions['no_assets_settings']) {
				return true;
			}
		}
		return false;
	}
	/**
	 * @param array $settings
	 *
	 * @return bool
	 */
	public static function isTestModeActive($settings = array())
    {
        if (defined('WPACU_IS_TEST_MODE_ACTIVE')) {
            return WPACU_IS_TEST_MODE_ACTIVE;
        }
        if (! $settings) {
            $settings = self::instance()->settings;
        }
        $wpacuIsTestModeActive = isset($settings['test_mode']) && $settings['test_mode'] && ! Menu::userCanManageAssets();
        define('WPACU_IS_TEST_MODE_ACTIVE', $wpacuIsTestModeActive);
        return $wpacuIsTestModeActive;
    }
	/**
	 * @return bool
	 */
	public static function currentUserCanViewAssetsList()
    {
	    if ( Main::instance()->settings['allow_manage_assets_to'] === 'chosen' && ! empty(Main::instance()->settings['allow_manage_assets_to_list']) ) {
		    $wpacuCurrentUserId = get_current_user_id();
		    if ( ! in_array( $wpacuCurrentUserId, Main::instance()->settings['allow_manage_assets_to_list'] ) ) {
			    return false; // the current logged-in admin is not in the list of "Allow managing assets to:"
		    }
	    }
	    return true;
    }
	/**
	 * @return bool
	 */
	public function frontendShow()
    {
        // The option is disabled
	    if (! $this->settings['frontend_show']) {
		    return false;
	    }
	    // The asset list is hidden via query string: /?wpacu_no_frontend_show
	    if (isset($_REQUEST['wpacu_no_frontend_show'])) {
	        return false;
        }
	    // Page loaded via Yellow Pencil Editor within an iframe? Do not show it as it's irrelevant there
        if (isset($_GET['yellow_pencil_frame'], $_GET['yp_page_type'])) {
            return false;
        }
	    // The option is enabled, but there are show exceptions, check if the list should be hidden
        if ($this->settings['frontend_show_exceptions']) {
	        $frontendShowExceptions = trim( $this->settings['frontend_show_exceptions'] );
	        // We want to make sure the RegEx rules will be working fine if certain characters (e.g. Thai ones) are used
	        $requestUriAsItIs = rawurldecode($_SERVER['REQUEST_URI']);
	        if ( strpos( $frontendShowExceptions, "\n" ) !== false ) {
		        foreach ( explode( "\n", $frontendShowExceptions ) as $frontendShowException ) {
			        $frontendShowException = trim($frontendShowException);
			        if ( strpos( $requestUriAsItIs, $frontendShowException ) !== false ) {
				        return false;
			        }
		        }
	        } elseif ( strpos( $requestUriAsItIs, $frontendShowExceptions ) !== false ) {
                return false;
	        }
        }
        // Allows managing assets to chosen admins and the user is not in the list
        if ( ! self::currentUserCanViewAssetsList() ) {
            return false;
        }
        return true;
    }
	/**
	 * Make administrator more aware if "TEST MODE" is enabled or not
	 */
	public function wpacuHtmlNoticeForAdmin()
	{
		add_action('wp_footer', static function() {
			if ((WPACU_GET_LOADED_ASSETS_ACTION === true) || (! apply_filters('wpacu_show_admin_console_notice', true)) || Plugin::preventAnyFrontendOptimization()) {
				return;
			}
			if ( ! (Menu::userCanManageAssets() && ! is_admin())) {
				return;
			}
			if (Main::instance()->settings['test_mode']) {
				$consoleMessage = sprintf(esc_html__('%s: "TEST MODE" ENABLED (any settings or unloads will be visible ONLY to you, the logged-in administrator)', 'wp-asset-clean-up'), WPACU_PLUGIN_TITLE);
				$testModeNotice = esc_html__('"Test Mode" is ENABLED. Any settings or unloads will be visible ONLY to you, the logged-in administrator.', 'wp-asset-clean-up');
			} else {
				$consoleMessage = sprintf(esc_html__('%s: "LIVE MODE" (test mode is not enabled, thus, all the plugin changes are visible for everyone: you, the logged-in administrator and the regular visitors)', 'wp-asset-clean-up'), WPACU_PLUGIN_TITLE);
				$testModeNotice = esc_html__('The website is in LIVE MODE as "Test Mode" is not enabled. All the plugin changes are visible for everyone: logged-in administrators and regular visitors.', 'wp-asset-clean-up');
			}
			?>