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