"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');
}
?>