first
This commit is contained in:
257
wp-content/plugins/wp-asset-clean-up/classes/AdminBar.php
Normal file
257
wp-content/plugins/wp-asset-clean-up/classes/AdminBar.php
Normal file
@ -0,0 +1,257 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class AdminBar
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class AdminBar
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'init', array( $this, 'topBar' ) );
|
||||
|
||||
// Hide top WordPress admin bar on request for debugging purposes and a cleared view of the tested page
|
||||
// This is done in /early-triggers.php within assetCleanUpNoLoad() function
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function topBar()
|
||||
{
|
||||
if (Menu::userCanManageAssets() && (! Main::instance()->settings['hide_from_admin_bar'])) {
|
||||
add_action( 'admin_bar_menu', array( $this, 'topBarInfo' ), 81 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $wp_admin_bar
|
||||
*/
|
||||
public function topBarInfo($wp_admin_bar)
|
||||
{
|
||||
$topTitle = WPACU_PLUGIN_TITLE;
|
||||
|
||||
$wpacuUnloadedAssetsStatus = false;
|
||||
|
||||
if (! is_admin()) {
|
||||
$markedCssListForUnload = isset(Main::instance()->allUnloadedAssets['styles']) ? array_unique(Main::instance()->allUnloadedAssets['styles']) : array();
|
||||
$markedJsListForUnload = isset(Main::instance()->allUnloadedAssets['scripts']) ? array_unique(Main::instance()->allUnloadedAssets['scripts']) : array();
|
||||
|
||||
// [wpacu_lite]
|
||||
// Do not print any irrelevant data from the Pro version such as hardcoded CSS/JS
|
||||
$markedCssListForUnload = array_filter($markedCssListForUnload, function($value) {
|
||||
if (strpos($value, 'wpacu_hardcoded_style_') === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
|
||||
$markedJsListForUnload = array_filter($markedJsListForUnload, function($value) {
|
||||
if (strpos($value, 'wpacu_hardcoded_script_') === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
// [/wpacu_lite]
|
||||
|
||||
$wpacuUnloadedAssetsStatus = (count($markedCssListForUnload) + count($markedJsListForUnload)) > 0;
|
||||
}
|
||||
|
||||
if ($wpacuUnloadedAssetsStatus) {
|
||||
$styleAttrType = Misc::getStyleTypeAttribute();
|
||||
|
||||
$cssStyle = <<<HTML
|
||||
<style {$styleAttrType}>
|
||||
#wpadminbar .wpacu-alert-sign-top-admin-bar {
|
||||
font-size: 20px;
|
||||
color: lightyellow;
|
||||
vertical-align: top;
|
||||
margin: -7px 0 0;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#wp-admin-bar-assetcleanup-plugin-unload-rules-notice-default .ab-item {
|
||||
min-width: 250px !important;
|
||||
}
|
||||
|
||||
#wp-admin-bar-assetcleanup-plugin-unload-rules-notice .ab-item > .dashicons-admin-plugins {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
line-height: normal;
|
||||
vertical-align: middle;
|
||||
margin-top: -2px;
|
||||
}
|
||||
</style>
|
||||
HTML;
|
||||
$topTitle .= $cssStyle . ' <span class="wpacu-alert-sign-top-admin-bar dashicons dashicons-filter"></span>';
|
||||
}
|
||||
|
||||
if (Main::instance()->settings['test_mode']) {
|
||||
$topTitle .= ' <span class="dashicons dashicons-admin-tools"></span> <strong>TEST MODE</strong> is <strong>ON</strong>';
|
||||
}
|
||||
|
||||
$goBackToCurrentUrl = '&_wp_http_referer=' . urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) );
|
||||
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'id' => 'assetcleanup-parent',
|
||||
'title' => $topTitle,
|
||||
'href' => esc_url(admin_url('admin.php?page=' . WPACU_PLUGIN_ID . '_settings'))
|
||||
));
|
||||
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-settings',
|
||||
'title' => __('Settings', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(admin_url( 'admin.php?page=' . WPACU_PLUGIN_ID . '_settings'))
|
||||
));
|
||||
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-clear-css-js-files-cache',
|
||||
'title' => __('Clear CSS/JS Files Cache', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(wp_nonce_url( admin_url( 'admin-post.php?action=assetcleanup_clear_assets_cache' . $goBackToCurrentUrl ), 'assetcleanup_clear_assets_cache' ))
|
||||
) );
|
||||
|
||||
// Only trigger in the front-end view
|
||||
if (! is_admin()) {
|
||||
if ( ! Misc::isHomePage() ) {
|
||||
// Not on the home page
|
||||
$homepageManageAssetsHref = Main::instance()->frontendShow()
|
||||
? get_site_url().'#wpacu_wrap_assets'
|
||||
: esc_url(admin_url( 'admin.php?page=' . WPACU_PLUGIN_ID . '_assets_manager&wpacu_for=homepage' ));
|
||||
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-homepage',
|
||||
'title' => esc_html__('Manage Homepage Assets', 'wp-asset-clean-up'),
|
||||
'href' => $homepageManageAssetsHref
|
||||
));
|
||||
} else {
|
||||
// On the home page
|
||||
// Front-end view is disabled! Go to Dashboard link
|
||||
if ( ! Main::instance()->frontendShow() ) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-homepage',
|
||||
'title' => esc_html__('Manage Homepage Assets', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(admin_url('admin.php?page=' . WPACU_PLUGIN_ID . '_assets_manager&wpacu_for=homepage')),
|
||||
'meta' => array('target' => '_blank')
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_admin()) {
|
||||
if (Main::instance()->frontendShow()) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-jump-to-assets-list',
|
||||
// language: alias of 'Manage Page Assets'
|
||||
'title' => esc_html__( 'Manage Current Page Assets', 'wp-asset-clean-up' ) . ' <span style="vertical-align: sub;" class="dashicons dashicons-arrow-down-alt"></span>',
|
||||
'href' => '#wpacu_wrap_assets'
|
||||
) );
|
||||
} elseif (is_singular()) {
|
||||
global $post;
|
||||
|
||||
if (isset($post->ID)) {
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-manage-page-assets-dashboard',
|
||||
// language: alias of 'Manage Page Assets'
|
||||
'title' => esc_html__('Manage Current Page Assets', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(admin_url('admin.php?page=' . WPACU_PLUGIN_ID . '_assets_manager&wpacu_post_id='.$post->ID)),
|
||||
'meta' => array('target' => '_blank')
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-bulk-unloaded',
|
||||
'title' => esc_html__('Bulk Changes', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(admin_url( 'admin.php?page=' . WPACU_PLUGIN_ID . '_bulk_unloads'))
|
||||
));
|
||||
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-overview',
|
||||
'title' => esc_html__('Overview', 'wp-asset-clean-up'),
|
||||
'href' => esc_url(admin_url( 'admin.php?page=' . WPACU_PLUGIN_ID . '_overview'))
|
||||
) );
|
||||
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-support-forum',
|
||||
'title' => esc_html__('Support Forum', 'wp-asset-clean-up'),
|
||||
'href' => 'https://wordpress.org/support/plugin/wp-asset-clean-up',
|
||||
'meta' => array('target' => '_blank')
|
||||
));
|
||||
|
||||
// [START LISTING UNLOADED ASSETS]
|
||||
if (! is_admin()) { // Frontend view (show any unloaded handles)
|
||||
$totalUnloadedAssets = count($markedCssListForUnload) + count($markedJsListForUnload);
|
||||
|
||||
if ($totalUnloadedAssets > 0) {
|
||||
$titleUnloadText = sprintf( _n( '%d unload asset rules took effect on this frontend page',
|
||||
'%d unload asset rules took effect on this frontend page', $totalUnloadedAssets, 'wp-asset-clean-up' ),
|
||||
$totalUnloadedAssets );
|
||||
|
||||
$wp_admin_bar->add_menu( array(
|
||||
'parent' => 'assetcleanup-parent',
|
||||
'id' => 'assetcleanup-asset-unload-rules-notice',
|
||||
'title' => '<span style="margin: -10px 0 0;" class="wpacu-alert-sign-top-admin-bar dashicons dashicons-filter"></span> '. $titleUnloadText,
|
||||
'href' => '#'
|
||||
) );
|
||||
|
||||
if ( count( $markedCssListForUnload ) > 0 ) {
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-asset-unload-rules-notice',
|
||||
'id' => 'assetcleanup-asset-unload-rules-css',
|
||||
'title' => esc_html__('CSS', 'wp-asset-clean-up'). ' ('.count( $markedCssListForUnload ).')',
|
||||
'href' => '#'
|
||||
));
|
||||
sort($markedCssListForUnload);
|
||||
|
||||
foreach ($markedCssListForUnload as $cssHandle) {
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-asset-unload-rules-css',
|
||||
'id' => 'assetcleanup-asset-unload-rules-css-'.$cssHandle,
|
||||
'title' => $cssHandle,
|
||||
'href' => esc_url(admin_url('admin.php?page=wpassetcleanup_overview#wpacu-overview-css-'.$cssHandle))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $markedJsListForUnload ) > 0 ) {
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-asset-unload-rules-notice',
|
||||
'id' => 'assetcleanup-asset-unload-rules-js',
|
||||
'title' => esc_html__('JavaScript', 'wp-asset-clean-up'). ' ('.count( $markedJsListForUnload ).')',
|
||||
'href' => '#'
|
||||
));
|
||||
sort($markedJsListForUnload);
|
||||
|
||||
foreach ($markedJsListForUnload as $jsHandle) {
|
||||
$wp_admin_bar->add_menu(array(
|
||||
'parent' => 'assetcleanup-asset-unload-rules-js',
|
||||
'id' => 'assetcleanup-asset-unload-rules-js-'.$jsHandle,
|
||||
'title' => $jsHandle,
|
||||
'href' => esc_url(admin_url('admin.php?page=wpassetcleanup_overview#wpacu-overview-js-'.$jsHandle))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// [END LISTING UNLOADED ASSETS]
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class AjaxSearchAutocomplete
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class AjaxSearchAutocomplete
|
||||
{
|
||||
/**
|
||||
* AjaxSearchAutocomplete constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action('admin_enqueue_scripts', array($this, 'enqueueScripts'));
|
||||
add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_autocomplete_search', array($this, 'wpAjaxSearch'));
|
||||
|
||||
self::maybePreventWpmlPluginFromFiltering();
|
||||
}
|
||||
|
||||
/**
|
||||
* "WPML Multilingual CMS" prevents the AJAX loader from "Load assets manager for:" from loading the results as they are
|
||||
* If a specific ID is put there, the post with that ID should be returned and not one of its translated posts with a different ID
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function maybePreventWpmlPluginFromFiltering()
|
||||
{
|
||||
if ( ! (isset($_REQUEST['action'], $_REQUEST['wpacu_term'], $GLOBALS['sitepress']) &&
|
||||
$_REQUEST['action'] === WPACU_PLUGIN_ID . '_autocomplete_search' &&
|
||||
$_REQUEST['wpacu_term'] &&
|
||||
Misc::isPluginActive('sitepress-multilingual-cms/sitepress.php')) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is called before "WPML Multilingual CMS" loads as we need to avoid any filtering of the search results
|
||||
// to avoid confusing the admin when managing the assets within "CSS & JS Manager" -- "Manage CSS/JS"
|
||||
|
||||
// Avoid retrieving the wrong (language related) post ID and title
|
||||
global $sitepress;
|
||||
remove_action( 'parse_query', array( $sitepress, 'parse_query' ) );
|
||||
|
||||
// Avoid retrieving the wrong (language related) permalink
|
||||
global $wp_filter;
|
||||
|
||||
if ( ! isset( $wp_filter['page_link']->callbacks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $wp_filter['page_link']->callbacks as $key => $values ) {
|
||||
if ( ! empty( $wp_filter['page_link']->callbacks ) ) {
|
||||
foreach ( $values as $values2 ) {
|
||||
if ( isset( $values2['function'][0] ) && $values2['function'][0] instanceof \WPML_URL_Filters ) {
|
||||
unset( $wp_filter['page_link']->callbacks[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Only valid for "CSS & JS Manager" -- "Manage CSS/JS" -- ("Posts" | "Pages" | "Custom Post Types" | "Media")
|
||||
*/
|
||||
public function enqueueScripts()
|
||||
{
|
||||
if (! isset($_REQUEST['wpacu_for'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isManageCssJsDash = isset($_GET['page']) && $_GET['page'] === WPACU_PLUGIN_ID.'_assets_manager';
|
||||
$subPage = isset($_GET['wpacu_sub_page']) ? $_GET['wpacu_sub_page'] : 'manage_css_js';
|
||||
|
||||
$loadAutoCompleteOnManageCssJsDash = ($isManageCssJsDash && $subPage === 'manage_css_js') &&
|
||||
in_array($_REQUEST['wpacu_for'], array('posts', 'pages', 'media-attachment', 'custom-post-types'));
|
||||
|
||||
if ( ! $loadAutoCompleteOnManageCssJsDash ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpacuFor = sanitize_text_field($_REQUEST['wpacu_for']);
|
||||
|
||||
switch ($wpacuFor) {
|
||||
case 'posts':
|
||||
$forPostType = 'post';
|
||||
break;
|
||||
case 'pages':
|
||||
$forPostType = 'page';
|
||||
break;
|
||||
case 'media-attachment':
|
||||
$forPostType = 'attachment';
|
||||
break;
|
||||
case 'custom-post-types':
|
||||
$forPostType = 'wpacu-custom-post-types';
|
||||
break;
|
||||
default:
|
||||
$forPostType = '';
|
||||
}
|
||||
|
||||
if ( ! $forPostType ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
OwnAssets::$ownAssets['scripts']['autocomplete_search']['handle'],
|
||||
plugins_url(OwnAssets::$ownAssets['scripts']['autocomplete_search']['rel_path'], WPACU_PLUGIN_FILE),
|
||||
array('jquery', 'jquery-ui-autocomplete'),
|
||||
OwnAssets::assetVer(OwnAssets::$ownAssets['scripts']['autocomplete_search']['rel_path']),
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(OwnAssets::$ownAssets['scripts']['autocomplete_search']['handle'], 'wpacu_autocomplete_search_obj', array(
|
||||
'ajax_url' => esc_url(admin_url('admin-ajax.php')),
|
||||
'ajax_nonce' => wp_create_nonce('wpacu_autocomplete_search_nonce'),
|
||||
'ajax_action' => WPACU_PLUGIN_ID . '_autocomplete_search',
|
||||
'post_type' => $forPostType,
|
||||
'redirect_to' => esc_url(admin_url('admin.php?page=wpassetcleanup_assets_manager&wpacu_for='.$wpacuFor.'&wpacu_post_id=post_id_here'))
|
||||
));
|
||||
|
||||
wp_enqueue_style(
|
||||
OwnAssets::$ownAssets['styles']['autocomplete_search_jquery_ui_custom']['handle'],
|
||||
plugins_url(OwnAssets::$ownAssets['styles']['autocomplete_search_jquery_ui_custom']['rel_path'], WPACU_PLUGIN_FILE),
|
||||
false, null, false
|
||||
);
|
||||
|
||||
$jqueryUiCustom = <<<CSS
|
||||
#wpacu-search-form-assets-manager input[type=text].ui-autocomplete-loading {
|
||||
background-position: 99% 6px;
|
||||
}
|
||||
CSS;
|
||||
wp_add_inline_style(OwnAssets::$ownAssets['styles']['autocomplete_search_jquery_ui_custom']['handle'], $jqueryUiCustom);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function wpAjaxSearch()
|
||||
{
|
||||
check_ajax_referer('wpacu_autocomplete_search_nonce', 'wpacu_security');
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$search_term = isset($_REQUEST['wpacu_term']) ? sanitize_text_field($_REQUEST['wpacu_term']) : '';
|
||||
$post_type = isset($_REQUEST['wpacu_post_type']) ? sanitize_text_field($_REQUEST['wpacu_post_type']) : '';
|
||||
|
||||
if ( $search_term === '' ) {
|
||||
echo wp_json_encode(array());
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
if ($post_type !== 'attachment') {
|
||||
// 'post', 'page', custom post types
|
||||
$queryDataByKeyword = array(
|
||||
'post_type' => $post_type,
|
||||
's' => $search_term,
|
||||
'post_status' => array( 'publish', 'private' ),
|
||||
'posts_per_page' => -1,
|
||||
'suppress_filters' => true
|
||||
);
|
||||
} else {
|
||||
// 'attachment'
|
||||
$search = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT ID FROM {$wpdb->posts} WHERE post_title = '%s'", $search_term ) );
|
||||
$queryDataByKeyword = array(
|
||||
'post_type' => 'attachment',
|
||||
'post_status' => 'inherit',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'post__in' => $search,
|
||||
'suppress_filters' => true
|
||||
);
|
||||
}
|
||||
|
||||
// Standard search
|
||||
$query = new \WP_Query($queryDataByKeyword);
|
||||
|
||||
// No results? Search by ID in case the admin put the post/page ID in the search box
|
||||
if (! $query->have_posts()) {
|
||||
// This one works for any post type, including 'attachment'
|
||||
$queryDataByID = array(
|
||||
'post_type' => $post_type,
|
||||
'p' => $search_term,
|
||||
'post_status' => array( 'publish', 'private' ),
|
||||
'posts_per_page' => -1,
|
||||
'post__in' => $search_term,
|
||||
'suppress_filters' => true
|
||||
);
|
||||
|
||||
$query = new \WP_Query($queryDataByID);
|
||||
}
|
||||
|
||||
if ($query->have_posts()) {
|
||||
$pageOnFront = $pageForPosts = false;
|
||||
|
||||
if ($post_type === 'page' && get_option('show_on_front') === 'page') {
|
||||
$pageOnFront = (int)get_option('page_on_front');
|
||||
$pageForPosts = (int)get_option('page_for_posts');
|
||||
}
|
||||
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$resultPostId = get_the_ID();
|
||||
$resultPostStatus = get_post_status($resultPostId);
|
||||
|
||||
$resultToShow = get_the_title() . ' / ID: '.$resultPostId;
|
||||
|
||||
if ($resultPostStatus === 'private') {
|
||||
$iconPrivate = '<span class="dashicons dashicons-lock"></span>';
|
||||
$resultToShow .= ' / '.$iconPrivate.' Private';
|
||||
}
|
||||
|
||||
// This is a page, and it was set as the homepage (point this out)
|
||||
if ($pageOnFront === $resultPostId) {
|
||||
$iconHome = '<span class="dashicons dashicons-admin-home"></span>';
|
||||
$resultToShow .= ' / '.$iconHome.' Homepage';
|
||||
}
|
||||
|
||||
if ($pageForPosts === $resultPostId) {
|
||||
$iconPost = '<span class="dashicons dashicons-admin-post"></span>';
|
||||
$resultToShow .= ' / '.$iconPost.' Posts page';
|
||||
}
|
||||
|
||||
$results[] = array(
|
||||
'id' => $resultPostId,
|
||||
'label' => $resultToShow,
|
||||
'link' => get_the_permalink()
|
||||
);
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
if (empty($results)) {
|
||||
echo 'no_results';
|
||||
wp_die();
|
||||
}
|
||||
|
||||
echo wp_json_encode($results);
|
||||
wp_die();
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class AssetsPagesManager
|
||||
* @package WpAssetCleanUp
|
||||
*
|
||||
* Actions taken within the Dashboard, inside the plugin area: "CSS & JS MANAGER" (main top menu) -- "MANAGE CSS/JS" (main tab)
|
||||
*/
|
||||
class AssetsPagesManager
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* AssetsPagesManager constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( Misc::getVar('get', 'page') !== WPACU_PLUGIN_ID . '_assets_manager' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpacuSubPage = (isset($_GET['wpacu_sub_page']) && $_GET['wpacu_sub_page']) ? $_GET['wpacu_sub_page'] : 'manage_css_js';
|
||||
|
||||
$this->data = array(
|
||||
'for' => 'homepage', // default
|
||||
'nonce_action' => WPACU_PLUGIN_ID . '_dash_assets_page_update_nonce_action',
|
||||
'nonce_name' => WPACU_PLUGIN_ID . '_dash_assets_page_update_nonce_name'
|
||||
);
|
||||
|
||||
$this->data['site_url'] = get_site_url();
|
||||
|
||||
if (isset($_GET['wpacu_for']) && $_GET['wpacu_for'] !== '') {
|
||||
$this->data['for'] = sanitize_text_field($_GET['wpacu_for']);
|
||||
}
|
||||
|
||||
$this->data['wpacu_post_id'] = (isset($_GET['wpacu_post_id']) && $_GET['wpacu_post_id']) ? (int)$_GET['wpacu_post_id'] : false;
|
||||
|
||||
if ($this->data['wpacu_post_id'] && $this->data['for'] === 'homepage') {
|
||||
// URI is like: /wp-admin/admin.php?page=wpassetcleanup_assets_manager&wpacu_post_id=POST_ID_HERE (without any "wpacu_for")
|
||||
// Proceed to detect the post type
|
||||
global $wpdb;
|
||||
$query = $wpdb->prepare("SELECT `post_type` FROM `{$wpdb->posts}` WHERE `ID`='%d'", $this->data['wpacu_post_id']);
|
||||
$requestedPostType = $wpdb->get_var($query);
|
||||
|
||||
if ($requestedPostType === 'post') {
|
||||
$this->data['for'] = 'posts';
|
||||
} elseif ($requestedPostType === 'page') {
|
||||
$this->data['for'] = 'posts';
|
||||
} elseif ($requestedPostType === 'attachment') {
|
||||
$this->data['for'] = 'media-attachment';
|
||||
} elseif ($requestedPostType !== '') {
|
||||
$this->data['for'] = 'custom-post-types';
|
||||
}
|
||||
}
|
||||
|
||||
if (Menu::isPluginPage()) {
|
||||
$this->data['page'] = sanitize_text_field($_GET['page']);
|
||||
}
|
||||
|
||||
$wpacuSettings = new Settings;
|
||||
$this->data['wpacu_settings'] = $wpacuSettings->getAll();
|
||||
$this->data['show_on_front'] = Misc::getShowOnFront();
|
||||
|
||||
if ($wpacuSubPage === 'manage_css_js' && in_array($this->data['for'], array('homepage', 'pages', 'posts', 'custom-post-types', 'media-attachment'))) {
|
||||
Misc::w3TotalCacheFlushObjectCache();
|
||||
|
||||
// Front page displays: A Static Page
|
||||
if ($this->data['for'] === 'homepage' && $this->data['show_on_front'] === 'page') {
|
||||
$this->data['page_on_front'] = get_option('page_on_front');
|
||||
|
||||
if ($this->data['page_on_front']) {
|
||||
$this->data['page_on_front_title'] = get_the_title($this->data['page_on_front']);
|
||||
}
|
||||
|
||||
$this->data['page_for_posts'] = get_option('page_for_posts');
|
||||
|
||||
if ($this->data['page_for_posts']) {
|
||||
$this->data['page_for_posts_title'] = get_the_title($this->data['page_for_posts']);
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. It could be the homepage tab loading a singular page set as the homepage in "Settings" -> "Reading"
|
||||
$anyPostId = (int)Misc::getVar('post', 'wpacu_manage_singular_page_id');
|
||||
|
||||
if ($this->data['for'] === 'homepage' && ! $anyPostId) {
|
||||
// "CSS & JS MANAGER" -- "Homepage" (e.g. "Your homepage displays" set as "Your latest posts")
|
||||
$this->homepageActions();
|
||||
} else {
|
||||
// "CSS & JS MANAGER" --> "MANAGE CSS/JS"
|
||||
// Case 1: "Homepage", if singular page set as the homepage in "Settings" -> "Reading")
|
||||
// Case 2: "Posts"
|
||||
// Case 3: "Pages"
|
||||
// Case 4: "Custom Post Types" (e.g. WooCommerce product)
|
||||
// Case 5: "Media" (attachment pages, rarely used)
|
||||
$this->singularPageActions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function homepageActions()
|
||||
{
|
||||
// Only continue if we are on the plugin's homepage edit mode
|
||||
if ( ! ( $this->data['for'] === 'homepage' && Misc::getVar('get', 'page') === WPACU_PLUGIN_ID . '_assets_manager' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update action?
|
||||
if (! empty($_POST) && Misc::getVar( 'post', 'wpacu_manage_home_page_assets', false ) ) {
|
||||
$wpacuNoLoadAssets = Misc::getVar( 'post', WPACU_PLUGIN_ID, array() );
|
||||
|
||||
$wpacuUpdate = new Update;
|
||||
|
||||
if ( ! (isset($_REQUEST[$this->data['nonce_name']])
|
||||
&& wp_verify_nonce($_REQUEST[$this->data['nonce_name']], $this->data['nonce_action'])) ) {
|
||||
add_action('wpacu_admin_notices', array($wpacuUpdate, 'changesNotMadeInvalidNonce'));
|
||||
return;
|
||||
}
|
||||
|
||||
// All good with the nonce? Do the changes!
|
||||
$wpacuUpdate->updateFrontPage( $wpacuNoLoadAssets );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any post type, including the custom ones
|
||||
*/
|
||||
public function singularPageActions()
|
||||
{
|
||||
$postId = (int)Misc::getVar('post', 'wpacu_manage_singular_page_id');
|
||||
|
||||
$isSingularPageEdit = $postId > 0 &&
|
||||
( Misc::getVar('get', 'page') === WPACU_PLUGIN_ID . '_assets_manager' &&
|
||||
in_array( $this->data['for'], array('homepage', 'pages', 'posts', 'custom-post-types', 'media-attachment' ) ) );
|
||||
|
||||
// Only continue if the form was submitted for a singular page
|
||||
// e.g. a post, a page (could be the homepage), a WooCommerce product page, any public custom post type
|
||||
if (! $isSingularPageEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! empty($_POST)) {
|
||||
// Update action?
|
||||
$wpacuNoLoadAssets = Misc::getVar( 'post', WPACU_PLUGIN_ID, array() );
|
||||
$wpacuSingularPageUpdate = Misc::getVar( 'post', 'wpacu_manage_singular_page_assets', false );
|
||||
|
||||
// Could Be an Empty Array as Well so just is_array() is enough to use
|
||||
if ( is_array( $wpacuNoLoadAssets ) && $wpacuSingularPageUpdate ) {
|
||||
$wpacuUpdate = new Update;
|
||||
|
||||
if ( ! (isset($_REQUEST[$this->data['nonce_name']])
|
||||
&& wp_verify_nonce($_REQUEST[$this->data['nonce_name']], $this->data['nonce_action'])) ) {
|
||||
add_action('wpacu_admin_notices', array($wpacuUpdate, 'changesNotMadeInvalidNonce'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($postId > 0) {
|
||||
$wpacuUpdate = new Update;
|
||||
$wpacuUpdate->savePosts($postId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in Menu.php (within "admin_menu" hook via "activeMenu" method)
|
||||
*/
|
||||
public function renderPage()
|
||||
{
|
||||
Main::instance()->parseTemplate('admin-page-assets-manager', $this->data, true);
|
||||
}
|
||||
}
|
218
wp-content/plugins/wp-asset-clean-up/classes/BulkChanges.php
Normal file
218
wp-content/plugins/wp-asset-clean-up/classes/BulkChanges.php
Normal file
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class BulkChanges
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class BulkChanges
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $wpacuFor = 'everywhere';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $wpacuPostType = 'post';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* Includes bulk unload rules, RegEx unloads & load exceptions
|
||||
*
|
||||
* BulkChanges constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->wpacuFor = sanitize_text_field(Misc::getVar('request', 'wpacu_for', $this->wpacuFor));
|
||||
$this->wpacuPostType = sanitize_text_field(Misc::getVar('request', 'wpacu_post_type', $this->wpacuPostType));
|
||||
|
||||
if (Misc::getVar('request', 'wpacu_update') == 1) {
|
||||
$this->update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCount()
|
||||
{
|
||||
$values = array();
|
||||
|
||||
if ($this->wpacuFor === 'everywhere') {
|
||||
$values = Main::instance()->getGlobalUnload();
|
||||
} elseif ($this->wpacuFor === 'post_types') {
|
||||
$values = Main::instance()->getBulkUnload('post_type', $this->wpacuPostType);
|
||||
}
|
||||
|
||||
if (isset($values['styles']) && ! empty($values['styles'])) {
|
||||
sort($values['styles']);
|
||||
}
|
||||
|
||||
if (isset($values['scripts']) && ! empty($values['scripts'])) {
|
||||
sort($values['scripts']);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function pageBulkUnloads()
|
||||
{
|
||||
$this->data['assets_info'] = Main::getHandlesInfo();
|
||||
$this->data['for'] = $this->wpacuFor;
|
||||
|
||||
if ($this->wpacuFor === 'post_types') {
|
||||
$this->data['post_type'] = $this->wpacuPostType;
|
||||
|
||||
// Get All Post Types
|
||||
$postTypes = get_post_types(array('public' => true));
|
||||
$this->data['post_types_list'] = Misc::filterPostTypesList( $postTypes );
|
||||
}
|
||||
|
||||
$this->data['values'] = $this->getCount();
|
||||
|
||||
$this->data['nonce_name'] = Update::NONCE_FIELD_NAME;
|
||||
$this->data['nonce_action'] = Update::NONCE_ACTION_NAME;
|
||||
|
||||
$this->data['plugin_settings'] = Main::instance()->settings;
|
||||
|
||||
Main::instance()->parseTemplate('admin-page-settings-bulk-changes', $this->data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $postTypes
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function filterPostTypesList($postTypes)
|
||||
{
|
||||
foreach ($postTypes as $postTypeKey => $postTypeValue) {
|
||||
// Exclude irrelevant custom post types
|
||||
if (in_array($postTypeKey, MetaBoxes::$noMetaBoxesForPostTypes)) {
|
||||
unset($postTypes[$postTypeKey]);
|
||||
}
|
||||
|
||||
// Polish existing values
|
||||
if ($postTypeKey === 'product' && Misc::isPluginActive('woocommerce/woocommerce.php')) {
|
||||
$postTypes[$postTypeKey] = 'product ⟶ WooCommerce';
|
||||
}
|
||||
}
|
||||
|
||||
return $postTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $postTypesList
|
||||
* @param $currentPostType
|
||||
*/
|
||||
public static function buildPostTypesListDd($postTypesList, $currentPostType)
|
||||
{
|
||||
$ddList = array();
|
||||
|
||||
foreach ($postTypesList as $postTypeKey => $postTypeValue) {
|
||||
if (in_array($postTypeKey, array('post', 'page', 'attachment'))) {
|
||||
$ddList['WordPress (default)'][$postTypeKey] = $postTypeValue;
|
||||
} else {
|
||||
$ddList['Custom Post Types (Singular pages)'][$postTypeKey] = $postTypeValue;
|
||||
|
||||
$list = Main::instance()->getBulkUnload('custom_post_type_archive_'.$postTypeKey);
|
||||
|
||||
// At least one of the buckets ('styles' or 'scripts') needs to contain something
|
||||
if (! empty($list['styles']) || ! empty($list['scripts'])) {
|
||||
$ddList['Custom Post Types (Archive pages)'][ 'wpacu_custom_post_type_archive_'.$postTypeKey ] = $postTypeValue. ' (archive page)';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<select id="wpacu_post_type_select" name="wpacu_post_type">
|
||||
<?php
|
||||
foreach ($ddList as $groupLabel => $groupPostTypesList) {
|
||||
echo '<optgroup label="'.$groupLabel.'">';
|
||||
|
||||
foreach ($groupPostTypesList as $postTypeKey => $postTypeValue) {
|
||||
?>
|
||||
<option <?php if ($currentPostType === $postTypeKey) { echo 'selected="selected"'; } ?> value="<?php echo esc_attr($postTypeKey); ?>"><?php echo esc_html($postTypeValue); ?></option>
|
||||
<?php
|
||||
}
|
||||
|
||||
echo '</optgroup>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
if ( ! Misc::getVar('post', 'wpacu_bulk_unloads_update_nonce') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
check_admin_referer('wpacu_bulk_unloads_update', 'wpacu_bulk_unloads_update_nonce');
|
||||
|
||||
$wpacuUpdate = new Update;
|
||||
|
||||
if ($this->wpacuFor === 'everywhere') {
|
||||
$removed = $wpacuUpdate->removeEverywhereUnloads(array(), array(), 'post');
|
||||
|
||||
if ($removed) {
|
||||
add_action('wpacu_admin_notices', array($this, 'noticeGlobalsRemoved'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->wpacuFor === 'post_types') {
|
||||
$removed = $wpacuUpdate->removeBulkUnloads($this->wpacuPostType);
|
||||
|
||||
if ($removed) {
|
||||
add_action('wpacu_admin_notices', array($this, 'noticePostTypesRemoved'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticeGlobalsRemoved()
|
||||
{
|
||||
?>
|
||||
<div class="updated notice wpacu-notice is-dismissible">
|
||||
<p><span class="dashicons dashicons-yes"></span>
|
||||
<?php
|
||||
_e('The selected styles/scripts were removed from the global unload list and they will now load in the pages/posts, unless you have other rules that would prevent them from loading.', 'wp-asset-clean-up');
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticePostTypesRemoved()
|
||||
{
|
||||
?>
|
||||
<div class="updated notice wpacu-notice is-dismissible">
|
||||
<p><span class="dashicons dashicons-yes"></span>
|
||||
<?php
|
||||
echo sprintf(
|
||||
__('The selected styles/scripts were removed from the unload list for <strong><u>%s</u></strong> post type and they will now load in the pages/posts, unless you have other rules that would prevent them from loading.', 'wp-asset-clean-up'),
|
||||
$this->wpacuPostType
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
629
wp-content/plugins/wp-asset-clean-up/classes/CleanUp.php
Normal file
629
wp-content/plugins/wp-asset-clean-up/classes/CleanUp.php
Normal file
@ -0,0 +1,629 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
|
||||
/**
|
||||
* Class CleanUp
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class CleanUp
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
// Is "Test Mode" is enabled and the page is viewed by a regular visitor (not administrator with plugin activation privileges)?
|
||||
// Stop here as the script will NOT PREVENT any of the elements below to load
|
||||
// They will load as they used to for the regular visitor while the admin debugs the website
|
||||
add_action('init', array($this, 'doClean'), 12);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doClean()
|
||||
{
|
||||
if ( ! method_exists( '\WpAssetCleanUp\Plugin', 'preventAnyFrontendOptimization' ) ) {
|
||||
return; // something's funny as, for some reason, on very rare occasions, the class is not found, so don't continue
|
||||
}
|
||||
|
||||
if ( (defined('WPACU_ALLOW_ONLY_UNLOAD_RULES') && WPACU_ALLOW_ONLY_UNLOAD_RULES) || Main::instance()->preventAssetsSettings() || Plugin::preventAnyFrontendOptimization() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = Main::instance()->settings;
|
||||
|
||||
// Remove "Really Simple Discovery (RSD)" link?
|
||||
if ($settings['remove_rsd_link'] == 1 || $settings['disable_xmlrpc'] === 'disable_all') {
|
||||
// <link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://yourwebsite.com/xmlrpc.php?rsd" />
|
||||
remove_action('wp_head', 'rsd_link');
|
||||
}
|
||||
|
||||
// Remove "Windows Live Writer" link?
|
||||
if ($settings['remove_wlw_link'] == 1) {
|
||||
// <link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://yourwebsite.com/wp-includes/wlwmanifest.xml">
|
||||
remove_action('wp_head', 'wlwmanifest_link');
|
||||
}
|
||||
|
||||
// Remove "REST API" link?
|
||||
if ($settings['remove_rest_api_link'] == 1) {
|
||||
// <link rel='https://api.w.org/' href='https://yourwebsite.com/wp-json/' />
|
||||
remove_action('wp_head', 'rest_output_link_wp_head');
|
||||
|
||||
// Removes the following printed within "Response headers":
|
||||
// <https://yourwebsite.com/wp-json/>; rel="https://api.w.org/"
|
||||
remove_action( 'template_redirect', 'rest_output_link_header', 11 );
|
||||
}
|
||||
|
||||
// Remove "Shortlink"?
|
||||
if ($settings['remove_shortlink'] == 1) {
|
||||
// <link rel='shortlink' href="https://yourdomain.com/?p=1">
|
||||
remove_action('wp_head', 'wp_shortlink_wp_head');
|
||||
|
||||
// link: <https://yourdomainname.com/wp-json/>; rel="https://api.w.org/", <https://yourdomainname.com/?p=[post_id_here]>; rel=shortlink
|
||||
remove_action('template_redirect', 'wp_shortlink_header', 11);
|
||||
}
|
||||
|
||||
// Remove "Post's Relational Links"?
|
||||
if ($settings['remove_posts_rel_links'] == 1) {
|
||||
// <link rel='prev' title='Title of adjacent post' href='https://yourdomain.com/adjacent-post-slug-here/' />
|
||||
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
|
||||
}
|
||||
|
||||
// Remove "WordPress version" tag?
|
||||
if ($settings['remove_wp_version']) {
|
||||
// <meta name="generator" content="WordPress 4.9.8" />
|
||||
remove_action('wp_head', 'wp_generator');
|
||||
|
||||
// also hide it from RSS
|
||||
add_filter('the_generator', '__return_false');
|
||||
}
|
||||
|
||||
if ($settings['disable_rss_feed']) {
|
||||
$this->doDisableRssFeed();
|
||||
}
|
||||
|
||||
// Remove Main RSS Feed Link?
|
||||
if ($settings['remove_main_feed_link']) {
|
||||
add_filter('feed_links_show_posts_feed', '__return_false');
|
||||
remove_action('wp_head', 'feed_links_extra', 3);
|
||||
}
|
||||
|
||||
// Remove Comment RSS Feed Link?
|
||||
if ($settings['remove_comment_feed_link']) {
|
||||
add_filter('feed_links_show_comments_feed', '__return_false');
|
||||
}
|
||||
|
||||
// Disable XML-RPC protocol support (partially or completely)
|
||||
if (in_array($settings['disable_xmlrpc'], array('disable_all', 'disable_pingback'))) {
|
||||
// Partially or Completely Options / Pingback will be disabled
|
||||
$this->disableXmlRpcPingback();
|
||||
|
||||
// Complete disable the service
|
||||
if ($settings['disable_xmlrpc'] === 'disable_all') {
|
||||
add_filter('xmlrpc_enabled', '__return_false');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in OptimiseAssets/OptimizeCommon.php
|
||||
*
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return string|string[]|null
|
||||
*/
|
||||
public static function cleanPingbackLinkRel($htmlSource)
|
||||
{
|
||||
$pingBackUrl = get_bloginfo('pingback_url');
|
||||
|
||||
$matchRegExps = array(
|
||||
'#<link rel=("|\')pingback("|\') href=("|\')'.$pingBackUrl.'("|\')( /|)>#',
|
||||
'#<link href=("|\')'.$pingBackUrl.'("|\') rel=("|\')pingback("|\')( /|)>#'
|
||||
);
|
||||
|
||||
foreach ($matchRegExps as $matchRegExp) {
|
||||
$htmlSource = preg_replace($matchRegExp, '', $htmlSource);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function disableXmlRpcPingback()
|
||||
{
|
||||
// Disable Pingback method
|
||||
add_filter('xmlrpc_methods', static function ($methods) {
|
||||
unset($methods['pingback.ping'], $methods['pingback.extensions.getPingbacks']);
|
||||
return $methods;
|
||||
} );
|
||||
|
||||
// Remove X-Pingback HTTP header
|
||||
add_filter('wp_headers', static function ($headers) {
|
||||
unset($headers['X-Pingback']);
|
||||
return $headers;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function removeMetaGenerators($htmlSource)
|
||||
{
|
||||
$fetchMethod = 'dom'; // 'regex' or 'dom'
|
||||
|
||||
if ( $fetchMethod === 'dom' && Misc::isDOMDocumentOn() && $htmlSource ) {
|
||||
$domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'removeMetaGenerators');
|
||||
|
||||
$metaTagsToStrip = array();
|
||||
|
||||
foreach ( $domTag->getElementsByTagName( 'meta' ) as $tagObject ) {
|
||||
$nameAttrValue = $tagObject->getAttribute( 'name' );
|
||||
|
||||
if ( $nameAttrValue === 'generator' ) {
|
||||
$outerTag = $outerTagRegExp = trim( Misc::getOuterHTML( $tagObject ) );
|
||||
|
||||
// As DOMDocument doesn't retrieve the exact string, some alterations to the RegEx have to be made
|
||||
// Leave no room for errors as all sort of characters can be within the "content" attribute
|
||||
$last2Chars = substr( $outerTag, - 2 );
|
||||
|
||||
if ( $last2Chars === '">' || $last2Chars === "'>" ) {
|
||||
$tagWithoutLastChar = substr( $outerTag, 0, - 1 );
|
||||
$outerTagRegExp = preg_quote( $tagWithoutLastChar, '/' ) . '(.*?)>';
|
||||
}
|
||||
|
||||
$outerTagRegExp = str_replace(
|
||||
array( '"', '<', '>' ),
|
||||
array( '("|\'|)', '(<|<)', '(>|>)' ),
|
||||
$outerTagRegExp
|
||||
);
|
||||
|
||||
if ( strpos( $outerTagRegExp, '<meta' ) !== false ) {
|
||||
$outerTagRegExp = str_replace('#', '\#', $outerTagRegExp);
|
||||
preg_match_all( '#' . $outerTagRegExp . '#si', $htmlSource, $matches );
|
||||
|
||||
if ( isset( $matches[0][0] ) && ! empty( $matches[0][0] ) && strip_tags( $matches[0][0] ) === '' ) {
|
||||
$metaTagsToStrip[$matches[0][0]] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$htmlSource = strtr($htmlSource, $metaTagsToStrip);
|
||||
|
||||
libxml_clear_errors();
|
||||
}
|
||||
|
||||
/* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source_for_remove_meta_generators', 'end' ); /* [/wpacu_timing] */
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
* @param bool $ignoreExceptions
|
||||
* @param $for
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
public static function removeHtmlComments($htmlSource, $ignoreExceptions = false)
|
||||
{
|
||||
if ( strpos($htmlSource, '<!--') === false || ! Misc::isDOMDocumentOn() ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'removeHtmlComments');
|
||||
|
||||
if (! $domTag) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$xpathComments = new \DOMXPath($domTag);
|
||||
$comments = $xpathComments->query('//comment()');
|
||||
|
||||
libxml_clear_errors();
|
||||
|
||||
if ($comments === null) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
preg_match_all('#<!--(.*?)-->#s', $htmlSource, $matchesRegExpComments);
|
||||
|
||||
// "comments" within tag attributes or script tags?
|
||||
// e.g. <script>var type='<!-- A comment here -->';</script>
|
||||
// e.g. <div data-info="This is just a <!-- comment --> text">Content here</div>
|
||||
$commentsWithinQuotes = array();
|
||||
|
||||
if (isset($matchesRegExpComments[1]) && count($matchesRegExpComments[1]) !== count($comments)) {
|
||||
preg_match_all('#=(|\s+)([\'"])(|\s+)<!--(.*?)-->(|\s+)([\'"])#s', $htmlSource, $matchesCommentsWithinQuotes);
|
||||
|
||||
if (isset($matchesCommentsWithinQuotes[0]) && ! empty($matchesCommentsWithinQuotes[0])) {
|
||||
foreach ($matchesCommentsWithinQuotes[0] as $matchedDataOriginal) {
|
||||
$matchedDataUpdated = str_replace(
|
||||
array('', '<!--', '-->'),
|
||||
array('--wpacu-space-del--', '--wpacu-start-comm--', '--wpacu-end-comm--'),
|
||||
$matchedDataOriginal
|
||||
);
|
||||
|
||||
$htmlSource = str_replace($matchedDataOriginal, $matchedDataUpdated, $htmlSource);
|
||||
|
||||
$commentsWithinQuotes[] = array(
|
||||
'original' => $matchedDataOriginal,
|
||||
'updated' => $matchedDataUpdated
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$stripCommentsList = array();
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
$entireComment = '<!--' . $comment->nodeValue . '-->';
|
||||
|
||||
// Do not strip MSIE conditional comments
|
||||
if ( strpos( $entireComment, '<!--<![endif]-->' ) !== false ||
|
||||
preg_match( '#<!--\[if(.*?)]>(.*?)<!-->#si', $entireComment ) ||
|
||||
preg_match( '#<!--\[if(.*?)\[endif]-->#si', $entireComment ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any exceptions set in "Strip HTML comments?" textarea?
|
||||
// $ignoreExceptions has to be set to false (as it is by default)
|
||||
if (! $ignoreExceptions && Main::instance()->settings['remove_html_comments_exceptions']) {
|
||||
$removeHtmlCommentsExceptions = trim(Main::instance()->settings['remove_html_comments_exceptions']);
|
||||
|
||||
if (strpos($removeHtmlCommentsExceptions, "\n") !== false) {
|
||||
foreach (explode("\n", $removeHtmlCommentsExceptions) as $removeCommExceptionPattern) {
|
||||
$removeCommExceptionPattern = trim($removeCommExceptionPattern);
|
||||
|
||||
if (stripos($entireComment, $removeCommExceptionPattern) !== false) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
} elseif (stripos($entireComment, $removeHtmlCommentsExceptions) !== false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($entireComment) < 200) {
|
||||
$stripCommentsList[ $entireComment ] = '';
|
||||
} else {
|
||||
$htmlSource = str_replace($entireComment, '', $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($stripCommentsList)) {
|
||||
$htmlSource = strtr( $htmlSource, $stripCommentsList );
|
||||
}
|
||||
|
||||
if (! empty($commentsWithinQuotes)) {
|
||||
foreach ($commentsWithinQuotes as $commentQuote) {
|
||||
$htmlSource = str_replace($commentQuote['updated'], $commentQuote['original'], $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $strContains
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanLinkTagFromHtmlSource($strContains, $htmlSource)
|
||||
{
|
||||
if (! is_array($strContains)) {
|
||||
$strContains = array($strContains);
|
||||
}
|
||||
|
||||
$strContains = array_map(function($value) {
|
||||
if (strpos($value, 'data-wpacu-style-handle') !== false) {
|
||||
return $value; // no need to use preg-quote
|
||||
}
|
||||
|
||||
return preg_quote($value, '/');
|
||||
}, $strContains);
|
||||
|
||||
preg_match_all(
|
||||
'#<link[^>]*('.implode('|', $strContains).')[^>].*(>)#Usmi',
|
||||
$htmlSource,
|
||||
$matchesSourcesFromTags
|
||||
);
|
||||
|
||||
if (empty($matchesSourcesFromTags)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($matchesSourcesFromTags as $matchesFromTag) {
|
||||
if (! (isset($matchesFromTag[0]) && $matchesFromTag[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$linkTag = $matchesFromTag[0];
|
||||
|
||||
if (stripos($linkTag, '<link') === 0 && substr($linkTag, -1) === '>' && strip_tags($linkTag) === '') {
|
||||
$htmlSource = str_replace($linkTag, '', $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $strContains
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanScriptTagFromHtmlSource($strContains, $htmlSource)
|
||||
{
|
||||
if (! is_array($strContains)) {
|
||||
$strContains = array($strContains);
|
||||
}
|
||||
|
||||
$strContains = array_map(function($value) {
|
||||
if (strpos($value, 'data-wpacu-script-handle') !== false) {
|
||||
return $value; // no need to use preg-quote
|
||||
}
|
||||
|
||||
return preg_quote($value, '/');
|
||||
}, $strContains);
|
||||
|
||||
preg_match_all(
|
||||
'#<script[^>]*('.implode('|', $strContains).')[^>].*(>)#Usmi',
|
||||
$htmlSource,
|
||||
$matchesSourcesFromTags
|
||||
);
|
||||
|
||||
if (empty($matchesSourcesFromTags)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($matchesSourcesFromTags as $matchesFromTag) {
|
||||
if (isset($matchesFromTag[0]) && $matchesFromTag[0] && strip_tags($matchesFromTag[0]) === '') {
|
||||
$htmlSource = str_replace($matchesFromTag[0] . '</script>', '', $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doDisableEmojis()
|
||||
{
|
||||
// Emojis Actions and Filters
|
||||
remove_action('admin_print_styles', 'print_emoji_styles');
|
||||
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
||||
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
||||
remove_action('wp_print_styles', 'print_emoji_styles');
|
||||
|
||||
remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
|
||||
remove_filter('the_content_feed', 'wp_staticize_emoji');
|
||||
remove_filter('comment_text_rss', 'wp_staticize_emoji');
|
||||
|
||||
// TinyMCE Emojis
|
||||
add_filter('tiny_mce_plugins', array($this, 'removeEmojisTinymce'));
|
||||
|
||||
add_filter('emoji_svg_url', '__return_false');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function removeEmojisTinymce($plugins)
|
||||
{
|
||||
if (is_array($plugins)) {
|
||||
return array_diff($plugins, array('wpemoji'));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doDisableOembed()
|
||||
{
|
||||
add_action('init', static function() {
|
||||
// Remove the REST API endpoint.
|
||||
remove_action('rest_api_init', 'wp_oembed_register_route');
|
||||
|
||||
// Turn off oEmbed auto discovery.
|
||||
add_filter('embed_oembed_discover', '__return_false');
|
||||
|
||||
// Don't filter oEmbed results.
|
||||
remove_filter('oembed_dataparse', 'wp_filter_oembed_result');
|
||||
|
||||
// Remove oEmbed discovery links.
|
||||
remove_action('wp_head', 'wp_oembed_add_discovery_links');
|
||||
|
||||
// Remove oEmbed-specific JavaScript from the front-end and back-end.
|
||||
remove_action('wp_head', 'wp_oembed_add_host_js');
|
||||
|
||||
add_filter('tiny_mce_plugins', static function ($plugins) {
|
||||
return array_diff($plugins, array('wpembed'));
|
||||
});
|
||||
|
||||
// Remove all embeds rewrite rules.
|
||||
add_filter('rewrite_rules_array', static function ($rules) {
|
||||
if ( ! empty($rules) ) {
|
||||
foreach ( $rules as $rule => $rewrite ) {
|
||||
if ( is_string($rewrite) && false !== strpos( $rewrite, 'embed=true' ) ) {
|
||||
unset( $rules[ $rule ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $rules;
|
||||
});
|
||||
|
||||
// Remove filter of the oEmbed result before any HTTP requests are made.
|
||||
remove_filter('pre_oembed_result', 'wp_filter_pre_oembed_result');
|
||||
}, 9999 );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doDisableRssFeed()
|
||||
{
|
||||
add_action('do_feed', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_rdf', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_rss', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_rss2', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_atom', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_rss2_comments', array($this, 'disabledRssFeedMsg'), 1);
|
||||
add_action('do_feed_atom_comments', array($this, 'disabledRssFeedMsg'), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function disabledRssFeedMsg()
|
||||
{
|
||||
$wpacuSettings = new Settings();
|
||||
$settingsArray = $wpacuSettings->getAll();
|
||||
|
||||
$feedDisableMsg = isset($settingsArray['disable_rss_feed_message']) ? $settingsArray['disable_rss_feed_message'] : '';
|
||||
|
||||
wp_die( __($feedDisableMsg, 'wp-asset-clean-up') );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function cleanUpHtmlOutputForAssetsCall()
|
||||
{
|
||||
if (isset($_GET['wpacu_clean_load'])) {
|
||||
// No Admin Bar
|
||||
add_filter('show_admin_bar', '__return_false', PHP_INT_MAX);
|
||||
}
|
||||
|
||||
// No Autoptimize
|
||||
if (! defined('AUTOPTIMIZE_NOBUFFER_OPTIMIZE')) {
|
||||
define( 'AUTOPTIMIZE_NOBUFFER_OPTIMIZE', true );
|
||||
}
|
||||
add_filter('autoptimize_filter_noptimize', '__return_false');
|
||||
|
||||
// Use less resources during CSS/JS fetching by preventing other plugins to interfere with the HTML output as it's completely unnecessary in this instance
|
||||
if (Misc::isPluginActive('autoptimize/autoptimize.php')) {
|
||||
foreach (array('autoptimize_html', 'autoptimize_css', 'autoptimize_js', 'autoptimize_cdn_url', 'autoptimize_optimize_logged') as $aoOption) {
|
||||
add_filter('pre_option_'.$aoOption, static function($value) { return ''; });
|
||||
}
|
||||
}
|
||||
|
||||
// No Fast Velocity Minify
|
||||
add_action('plugins_loaded', static function() {
|
||||
remove_action( 'setup_theme', 'fastvelocity_process_frontend' );
|
||||
}, PHP_INT_MAX);
|
||||
|
||||
// No WP Rocket (Minify / Concatenate)
|
||||
add_filter( 'get_rocket_option_minify_css', '__return_false' );
|
||||
add_filter( 'get_rocket_option_minify_concatenate_css', '__return_false' );
|
||||
|
||||
add_filter( 'get_rocket_option_minify_js', '__return_false' );
|
||||
add_filter( 'get_rocket_option_minify_concatenate_js', '__return_false' );
|
||||
|
||||
// No W3 Total Cache: Minify
|
||||
add_filter('w3tc_minify_enable', '__return_false');
|
||||
|
||||
// [NO SG Optimiser]
|
||||
self::filterSGOptions();
|
||||
|
||||
// Emulate page builder param to view page with no SG Optimiser on request
|
||||
// Extra params to be used in case 'SG Optimiser' is called before Asset CleanUp: 'fl_builder', 'vcv-action', 'et_fb', 'ct_builder', 'tve'
|
||||
add_filter('sgo_pb_params', static function($pbParams) {
|
||||
$pbParams[] = WPACU_LOAD_ASSETS_REQ_KEY; // fetching assets
|
||||
$pbParams[] = 'wpacu_clean_load'; // loading the page unoptimized for debugging purposes
|
||||
return $pbParams;
|
||||
});
|
||||
|
||||
// Fallback in case SG Optimizer is triggered BEFORE Asset CleanUp and the filter above will not work
|
||||
add_filter('sgo_css_combine_exclude', array($this, 'allCssHandles'));
|
||||
add_filter('sgo_css_minify_exclude', array($this, 'allCssHandles'));
|
||||
add_filter('sgo_js_minify_exclude', array($this, 'allJsHandles'));
|
||||
add_filter('sgo_js_async_exclude', array($this, 'allJsHandles'));
|
||||
|
||||
add_filter('sgo_html_minify_exclude_params', static function ($excludeParams) {
|
||||
$excludeParams[] = WPACU_LOAD_ASSETS_REQ_KEY; // fetching assets
|
||||
$excludeParams[] = 'wpacu_clean_load'; // loading the page unoptimized for debugging purposes
|
||||
return $excludeParams;
|
||||
});
|
||||
// [/NO SG Optimiser]
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function filterSGOptions()
|
||||
{
|
||||
// SG Optimizer Plugin
|
||||
$sgOptimizerMapping = array(
|
||||
'autoflush' => 'siteground_optimizer_autoflush_cache',
|
||||
'dynamic-cache' => 'siteground_optimizer_enable_cache',
|
||||
'memcache' => 'siteground_optimizer_enable_memcached',
|
||||
'ssl-fix' => 'siteground_optimizer_fix_insecure_content',
|
||||
'html' => 'siteground_optimizer_optimize_html',
|
||||
'js' => 'siteground_optimizer_optimize_javascript',
|
||||
'js-async' => 'siteground_optimizer_optimize_javascript_async',
|
||||
'css' => 'siteground_optimizer_optimize_css',
|
||||
'combine-css' => 'siteground_optimizer_combine_css',
|
||||
'querystring' => 'siteground_optimizer_remove_query_strings',
|
||||
'emojis' => 'siteground_optimizer_disable_emojis',
|
||||
'images' => 'siteground_optimizer_optimize_images',
|
||||
'lazyload_images' => 'siteground_optimizer_lazyload_images',
|
||||
'lazyload_gravatars' => 'siteground_optimizer_lazyload_gravatars',
|
||||
'lazyload_thumbnails' => 'siteground_optimizer_lazyload_thumbnails',
|
||||
'lazyload_responsive' => 'siteground_optimizer_lazyload_responsive',
|
||||
'lazyload_textwidgets' => 'siteground_optimizer_lazyload_textwidgets',
|
||||
'ssl' => 'siteground_optimizer_ssl_enabled',
|
||||
'gzip' => 'siteground_optimizer_enable_gzip_compression',
|
||||
'browser-caching' => 'siteground_optimizer_enable_browser_caching',
|
||||
);
|
||||
|
||||
foreach ($sgOptimizerMapping as $optionName) {
|
||||
add_filter('pre_option_'.$optionName, '__return_false');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function allCssHandles()
|
||||
{
|
||||
global $wp_styles;
|
||||
|
||||
$allCssHandles = array();
|
||||
|
||||
if (isset($wp_styles->registered) && ! empty($wp_styles->registered)) {
|
||||
$allCssHandles = array_keys($wp_styles->registered);
|
||||
}
|
||||
|
||||
return $allCssHandles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function allJsHandles()
|
||||
{
|
||||
global $wp_scripts;
|
||||
|
||||
$allJsHandles = array();
|
||||
|
||||
if (isset($wp_scripts->registered) && ! empty($wp_scripts->registered)) {
|
||||
$allJsHandles = array_keys($wp_scripts->registered);
|
||||
}
|
||||
|
||||
return $allJsHandles;
|
||||
}
|
||||
}
|
273
wp-content/plugins/wp-asset-clean-up/classes/Debug.php
Normal file
273
wp-content/plugins/wp-asset-clean-up/classes/Debug.php
Normal file
@ -0,0 +1,273 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
|
||||
/**
|
||||
* Class Debug
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Debug
|
||||
{
|
||||
/**
|
||||
* Debug constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (isset($_GET['wpacu_debug'])) {
|
||||
add_action('wp_footer', array($this, 'showDebugOptionsFront'), PHP_INT_MAX);
|
||||
}
|
||||
|
||||
foreach(array('wp', 'admin_init') as $wpacuActionHook) {
|
||||
add_action( $wpacuActionHook, static function() {
|
||||
if (isset( $_GET['wpacu_get_cache_dir_size'] ) && Menu::userCanManageAssets()) {
|
||||
self::printCacheDirInfo();
|
||||
}
|
||||
|
||||
// For debugging purposes
|
||||
if (isset($_GET['wpacu_get_already_minified']) && Menu::userCanManageAssets()) {
|
||||
echo '<pre>'; print_r(OptimizeCommon::getAlreadyMarkedAsMinified()); echo '</pre>';
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_GET['wpacu_remove_already_minified']) && Menu::userCanManageAssets()) {
|
||||
echo '<pre>'; print_r(OptimizeCommon::removeAlreadyMarkedAsMinified()); echo '</pre>';
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_GET['wpacu_limit_already_minified']) && Menu::userCanManageAssets()) {
|
||||
OptimizeCommon::limitAlreadyMarkedAsMinified();
|
||||
echo '<pre>'; print_r(OptimizeCommon::getAlreadyMarkedAsMinified()); echo '</pre>';
|
||||
exit();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function showDebugOptionsFront()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$markedCssListForUnload = array_unique(Main::instance()->allUnloadedAssets['styles']);
|
||||
$markedJsListForUnload = array_unique(Main::instance()->allUnloadedAssets['scripts']);
|
||||
|
||||
$allDebugOptions = array(
|
||||
// [For CSS]
|
||||
'wpacu_no_css_unload' => 'Do not apply any CSS unload rules',
|
||||
'wpacu_no_css_minify' => 'Do not minify any CSS',
|
||||
'wpacu_no_css_combine' => 'Do not combine any CSS',
|
||||
|
||||
'wpacu_no_css_preload_basic' => 'Do not preload any CSS (Basic)',
|
||||
// [/For CSS]
|
||||
|
||||
// [For JS]
|
||||
'wpacu_no_js_unload' => 'Do not apply any JavaScript unload rules',
|
||||
'wpacu_no_js_minify' => 'Do not minify any JavaScript',
|
||||
'wpacu_no_js_combine' => 'Do not combine any JavaScript',
|
||||
|
||||
'wpacu_no_js_preload_basic' => 'Do not preload any JS (Basic)',
|
||||
// [/For JS]
|
||||
|
||||
// Others
|
||||
'wpacu_no_frontend_show' => 'Do not show the bottom CSS/JS managing list',
|
||||
'wpacu_no_admin_bar' => 'Do not show the admin bar',
|
||||
'wpacu_no_html_changes' => 'Do not alter the HTML DOM (this will also load all assets non-minified and non-combined)',
|
||||
);
|
||||
?>
|
||||
<style <?php echo Misc::getStyleTypeAttribute(); ?>>
|
||||
<?php echo file_get_contents(WPACU_PLUGIN_DIR.'/assets/wpacu-debug.css'); ?>
|
||||
</style>
|
||||
|
||||
<script <?php echo Misc::getScriptTypeAttribute(); ?>>
|
||||
<?php echo file_get_contents(WPACU_PLUGIN_DIR.'/assets/wpacu-debug.js'); ?>
|
||||
</script>
|
||||
|
||||
<div id="wpacu-debug-options">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">
|
||||
<p>View the page with the following options <strong>disabled</strong> (for debugging purposes):</p>
|
||||
<form method="post">
|
||||
<ul class="wpacu-options">
|
||||
<?php
|
||||
foreach ($allDebugOptions as $debugKey => $debugText) {
|
||||
?>
|
||||
<li>
|
||||
<label><input type="checkbox"
|
||||
name="<?php echo esc_attr($debugKey); ?>"
|
||||
<?php if ( ! empty($_GET) && array_key_exists($debugKey, $_GET) ) { echo 'checked="checked"'; } ?> /> <?php echo esc_html($debugText); ?></label>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<div>
|
||||
<input type="submit"
|
||||
value="Preview this page with the changes made above" />
|
||||
</div>
|
||||
<input type="hidden" name="wpacu_debug" value="on" />
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<div style="margin: 0 0 10px; padding: 10px 0;">
|
||||
<strong>CSS handles marked for unload:</strong>
|
||||
<?php
|
||||
if (! empty($markedCssListForUnload)) {
|
||||
sort($markedCssListForUnload);
|
||||
$markedCssListForUnloadFiltered = array_map(static function($handle) {
|
||||
return '<span style="color: darkred;">'.esc_html($handle).'</span>';
|
||||
}, $markedCssListForUnload);
|
||||
echo implode(' / ', $markedCssListForUnloadFiltered);
|
||||
} else {
|
||||
echo 'None';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div style="margin: 0 0 10px; padding: 10px 0;">
|
||||
<strong>JS handles marked for unload:</strong>
|
||||
<?php
|
||||
if (! empty($markedJsListForUnload)) {
|
||||
sort($markedJsListForUnload);
|
||||
$markedJsListForUnloadFiltered = array_map(static function($handle) {
|
||||
return '<span style="color: darkred;">'.esc_html($handle).'</span>';
|
||||
}, $markedJsListForUnload);
|
||||
|
||||
echo implode(' / ', $markedJsListForUnloadFiltered);
|
||||
} else {
|
||||
echo 'None';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div style="margin: 0 0 10px; padding: 10px 0;">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li style="margin-bottom: 10px;">Dequeue any chosen styles (.css): <?php echo Misc::printTimingFor('filter_dequeue_styles', '{wpacu_filter_dequeue_styles_exec_time} ({wpacu_filter_dequeue_styles_exec_time_sec})'); ?></li>
|
||||
<li style="margin-bottom: 20px;">Dequeue any chosen scripts (.js): <?php echo Misc::printTimingFor('filter_dequeue_scripts', '{wpacu_filter_dequeue_scripts_exec_time} ({wpacu_filter_dequeue_scripts_exec_time_sec})'); ?></li>
|
||||
|
||||
<li style="margin-bottom: 10px;">Prepare CSS files to optimize: {wpacu_prepare_optimize_files_css_exec_time} ({wpacu_prepare_optimize_files_css_exec_time_sec})</li>
|
||||
<li style="margin-bottom: 20px;">Prepare JS files to optimize: {wpacu_prepare_optimize_files_js_exec_time} ({wpacu_prepare_optimize_files_js_exec_time_sec})</li>
|
||||
|
||||
<li style="margin-bottom: 10px;">OptimizeCommon - HTML alteration via <em>wp_loaded</em>: {wpacu_alter_html_source_exec_time} ({wpacu_alter_html_source_exec_time_sec})
|
||||
<ul id="wpacu-debug-timing">
|
||||
<li style="margin-top: 10px; margin-bottom: 10px;"> OptimizeCSS: {wpacu_alter_html_source_for_optimize_css_exec_time} ({wpacu_alter_html_source_for_optimize_css_exec_time_sec})
|
||||
<ul>
|
||||
<li>Google Fonts Optimization/Removal: {wpacu_alter_html_source_for_google_fonts_optimization_removal_exec_time}</li>
|
||||
<li>From CSS file to Inline: {wpacu_alter_html_source_for_inline_css_exec_time}</li>
|
||||
<li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_css_exec_time}</li>
|
||||
<li>Preloads: {wpacu_alter_html_source_for_preload_css_exec_time}</li>
|
||||
<!-- -->
|
||||
<li>Combine: {wpacu_alter_html_source_for_combine_css_exec_time}</li>
|
||||
<li>Minify Inline Tags: {wpacu_alter_html_source_for_minify_inline_style_tags_exec_time}</li>
|
||||
<li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_css_exec_time}</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>OptimizeJs: {wpacu_alter_html_source_for_optimize_js_exec_time} ({wpacu_alter_html_source_for_optimize_js_exec_time_sec})
|
||||
<ul>
|
||||
<li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_js_exec_time}</li>
|
||||
<li>Preloads: {wpacu_alter_html_source_for_preload_js_exec_time}</li>
|
||||
<!-- -->
|
||||
<li>Combine: {wpacu_alter_html_source_for_combine_js_exec_time}</li>
|
||||
<li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_js_exec_time}</li>
|
||||
<li>Move any inline wih jQuery code after jQuery library: {wpacu_alter_html_source_move_inline_jquery_after_src_tag_exec_time}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>HTML CleanUp: {wpacu_alter_html_source_cleanup_exec_time}
|
||||
<ul>
|
||||
<li>Strip HTML Comments: {wpacu_alter_html_source_for_remove_html_comments_exec_time}</li>
|
||||
<li>Remove Generator Meta Tags: {wpacu_alter_html_source_for_remove_meta_generators_exec_time}</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li style="margin-bottom: 10px;">Output CSS & JS Management List: {wpacu_output_css_js_manager_exec_time} ({wpacu_output_css_js_manager_exec_time_sec})</li>
|
||||
|
||||
<!-- -->
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function printCacheDirInfo()
|
||||
{
|
||||
$assetCleanUpCacheDirRel = OptimizeCommon::getRelPathPluginCacheDir();
|
||||
$assetCleanUpCacheDir = WP_CONTENT_DIR . $assetCleanUpCacheDirRel;
|
||||
|
||||
echo '<h3>'.WPACU_PLUGIN_TITLE.': Caching Directory Stats</h3>';
|
||||
|
||||
if (is_dir($assetCleanUpCacheDir)) {
|
||||
$printCacheDirOutput = '<em>'.str_replace($assetCleanUpCacheDirRel, '<strong>'.$assetCleanUpCacheDirRel.'</strong>', $assetCleanUpCacheDir).'</em>';
|
||||
|
||||
if (! is_writable($assetCleanUpCacheDir)) {
|
||||
echo '<span style="color: red;">'.
|
||||
'The '.wp_kses($printCacheDirOutput, array('em' => array(), 'strong' => array())).' directory is <em>not writable</em>.</span>'.
|
||||
'<br /><br />';
|
||||
} else {
|
||||
echo '<span style="color: green;">The '.wp_kses($printCacheDirOutput, array('em' => array(), 'strong' => array())).' directory is <em>writable</em>.</span>' . '<br /><br />';
|
||||
}
|
||||
|
||||
$dirItems = new \RecursiveDirectoryIterator( $assetCleanUpCacheDir,
|
||||
\RecursiveDirectoryIterator::SKIP_DOTS );
|
||||
|
||||
$totalFiles = 0;
|
||||
$totalSize = 0;
|
||||
|
||||
foreach (
|
||||
new \RecursiveIteratorIterator( $dirItems, \RecursiveIteratorIterator::SELF_FIRST,
|
||||
\RecursiveIteratorIterator::CATCH_GET_CHILD ) as $item
|
||||
) {
|
||||
if ($item->isDir()) {
|
||||
echo '<br />';
|
||||
|
||||
$appendAfter = ' - ';
|
||||
|
||||
if (is_writable($item)) {
|
||||
$appendAfter .= ' <em><strong>writable</strong> directory</em>';
|
||||
} else {
|
||||
$appendAfter .= ' <em><strong style="color: red;">not writable</strong> directory</em>';
|
||||
}
|
||||
} elseif ($item->isFile()) {
|
||||
$appendAfter = '(<em>'.Misc::formatBytes($item->getSize()).'</em>)';
|
||||
|
||||
echo ' - ';
|
||||
}
|
||||
|
||||
echo wp_kses($item.' '.$appendAfter, array(
|
||||
'em' => array(),
|
||||
'strong' => array('style' => array()),
|
||||
'br' => array(),
|
||||
'span' => array('style' => array())
|
||||
))
|
||||
|
||||
.'<br />';
|
||||
|
||||
if ( $item->isFile() ) {
|
||||
$totalSize += $item->getSize();
|
||||
$totalFiles ++;
|
||||
}
|
||||
}
|
||||
|
||||
echo '<br />'.'Total Files: <strong>'.$totalFiles.'</strong> / Total Size: <strong>'.Misc::formatBytes($totalSize).'</strong>';
|
||||
} else {
|
||||
echo 'The directory does not exists.';
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
104
wp-content/plugins/wp-asset-clean-up/classes/FileSystem.php
Normal file
104
wp-content/plugins/wp-asset-clean-up/classes/FileSystem.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
|
||||
|
||||
/**
|
||||
* Class FileSystem
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class FileSystem
|
||||
{
|
||||
/**
|
||||
* @return bool|\WP_Filesystem_Direct
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
// Set the permission constants if not already set.
|
||||
if ( ! defined('FS_CHMOD_DIR') ) {
|
||||
define('FS_CHMOD_DIR', fileperms(ABSPATH) & 0777 | 0755);
|
||||
}
|
||||
|
||||
if ( ! defined('FS_CHMOD_FILE') ) {
|
||||
define('FS_CHMOD_FILE', fileperms(ABSPATH . 'index.php') & 0777 | 0644);
|
||||
}
|
||||
|
||||
if (! defined('WPACU_FS_USED') && ! class_exists('\WP_Filesystem_Base') && ! class_exists('\WP_Filesystem_Direct')) {
|
||||
$wpFileSystemBase = ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
||||
$wpFileSystemDirect = ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
|
||||
|
||||
if (is_file($wpFileSystemBase) && is_file($wpFileSystemDirect)) {
|
||||
// Make sure to use the 'direct' method as it's the most effective in this scenario
|
||||
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
|
||||
define('WPACU_FS_USED', true);
|
||||
} else {
|
||||
// Do not use WordPress FileSystem Direct (fallback to default PHP functions)
|
||||
define('WPACU_FS_USED', false);
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('WPACU_FS_USED') && WPACU_FS_USED === true) {
|
||||
return new \WP_Filesystem_Direct( new \StdClass() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localPathToFile
|
||||
* @param string $alter
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public static function fileGetContents($localPathToFile, $alter = '')
|
||||
{
|
||||
// ONLY relevant for CSS files
|
||||
if ($alter === 'combine_css_imports') {
|
||||
// This custom class does not minify as it's custom-made for combining @import
|
||||
$optimizer = new \WpAssetCleanUp\OptimiseAssets\CombineCssImports($localPathToFile);
|
||||
return $optimizer->minify();
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if (! self::init()) {
|
||||
return @file_get_contents($localPathToFile);
|
||||
}
|
||||
|
||||
return self::init()->get_contents($localPathToFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localPathToFile
|
||||
* @param $contents
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function filePutContents($localPathToFile, $contents)
|
||||
{
|
||||
if ( (strpos($localPathToFile, WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir()) !== false && ! is_dir(dirname($localPathToFile)))
|
||||
|| (strpos($localPathToFile, WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir()) !== false && ! is_dir(dirname($localPathToFile)))
|
||||
) {
|
||||
$dirToCreate = dirname( $localPathToFile );
|
||||
try {
|
||||
mkdir( $dirToCreate, FS_CHMOD_DIR, true );
|
||||
} catch (\Exception $e) {
|
||||
error_log( WPACU_PLUGIN_TITLE . ': Could not make directory ' . $dirToCreate . ' / Error: '.$e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
try {
|
||||
if ( ! self::init() ) {
|
||||
$return = file_put_contents( $localPathToFile, $contents );
|
||||
} else {
|
||||
$return = self::init()->put_contents( $localPathToFile, $contents, FS_CHMOD_FILE );
|
||||
}
|
||||
} catch ( \Exception $e ) {
|
||||
error_log( WPACU_PLUGIN_TITLE . ': Could not write to ' . $localPathToFile . ' / Error: '.$e->getMessage() );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
883
wp-content/plugins/wp-asset-clean-up/classes/HardcodedAssets.php
Normal file
883
wp-content/plugins/wp-asset-clean-up/classes/HardcodedAssets.php
Normal file
@ -0,0 +1,883 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
|
||||
|
||||
/**
|
||||
* Class HardcodedAssets
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class HardcodedAssets
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
add_action( 'init', static function() {
|
||||
if (Main::instance()->isGetAssetsCall) {
|
||||
// Case 1: An AJAX call is made from the Dashboard
|
||||
self::initBufferingForAjaxCallFromTheDashboard();
|
||||
} elseif (self::useBufferingForEditFrontEndView()) {
|
||||
// Case 2: The logged-in admin manages the assets from the front-end view
|
||||
self::initBufferingForFrontendManagement();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function initBufferingForAjaxCallFromTheDashboard()
|
||||
{
|
||||
ob_start();
|
||||
|
||||
add_action('shutdown', static function() {
|
||||
$htmlSource = '';
|
||||
|
||||
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
|
||||
// that buffer's output into the final output.
|
||||
$htmlSourceLevel = ob_get_level();
|
||||
|
||||
for ($wpacuI = 0; $wpacuI < $htmlSourceLevel; $wpacuI++) {
|
||||
$htmlSource .= ob_get_clean();
|
||||
}
|
||||
|
||||
$anyHardCodedAssets = HardcodedAssets::getAll($htmlSource); // Fetch all for this type of request
|
||||
|
||||
echo str_replace('{wpacu_hardcoded_assets}', $anyHardCodedAssets, $htmlSource);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function initBufferingForFrontendManagement()
|
||||
{
|
||||
// Used to print the hardcoded CSS/JS
|
||||
ob_start();
|
||||
|
||||
add_action('shutdown', static function() {
|
||||
if (! defined('NEXTEND_SMARTSLIDER_3_URL_PATH')) {
|
||||
ob_flush();
|
||||
}
|
||||
|
||||
$htmlSource = '';
|
||||
|
||||
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
|
||||
// that buffer's output into the final output.
|
||||
$htmlSourceLevel = ob_get_level();
|
||||
|
||||
for ($wpacuI = 0; $wpacuI < $htmlSourceLevel; $wpacuI++) {
|
||||
$htmlSource .= ob_get_clean();
|
||||
}
|
||||
|
||||
echo OptimizeCommon::alterHtmlSource($htmlSource);
|
||||
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function useBufferingForEditFrontEndView()
|
||||
{
|
||||
// The logged-in admin needs to be outside the Dashboard (in the front-end view)
|
||||
// "Manage in the Front-end" is enabled in "Settings" -> "Plugin Usage Preferences"
|
||||
return (Main::instance()->frontendShow() && ! is_admin() && Menu::userCanManageAssets() && ! Main::instance()->isGetAssetsCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
* @param bool $encodeIt - if set to "false", it's mostly for testing purposes
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function getAll($htmlSource, $encodeIt = true)
|
||||
{
|
||||
$htmlSourceAlt = CleanUp::removeHtmlComments($htmlSource, true);
|
||||
|
||||
$collectLinkStyles = true; // default
|
||||
$collectScripts = true; // default
|
||||
|
||||
$hardCodedAssets = array(
|
||||
'link_and_style_tags' => array(), // LINK (rel="stylesheet") & STYLE (inline)
|
||||
'script_nosrc_and_inline_tags' => array(), // SCRIPT (with "src" attribute) & SCRIPT (inline)
|
||||
);
|
||||
|
||||
$matchesSourcesFromTags = array();
|
||||
|
||||
$stickToRegEx = true;
|
||||
|
||||
if ( $collectLinkStyles ) {
|
||||
if ( ! $stickToRegEx && Misc::isDOMDocumentOn() ) {
|
||||
$domDoc = Misc::initDOMDocument();
|
||||
$domDoc->loadHTML($htmlSourceAlt);
|
||||
|
||||
$selector = new \DOMXPath($domDoc);
|
||||
|
||||
$domTagQuery = $selector->query('//link[@rel="stylesheet"]|//style|//script|//noscript');
|
||||
|
||||
if (count($domTagQuery) > 1) {
|
||||
foreach($domTagQuery as $tagFound) {
|
||||
$tagType = in_array($tagFound->nodeName, array('link', 'style')) ? 'css' : 'js';
|
||||
|
||||
if (self::skipTagIfNotRelevant( Misc::getOuterHTML( $tagFound ), 'whole_tag', $tagType)) {
|
||||
continue; // no point in wasting more resources as the tag will never be shown, since it's irrelevant
|
||||
}
|
||||
|
||||
if ( $tagFound->hasAttributes() ) {
|
||||
foreach ( $tagFound->attributes as $attr ) {
|
||||
if ( self::skipTagIfNotRelevant( $attr->nodeName, 'attribute', $tagType ) ) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($tagFound->nodeName === 'link') {
|
||||
if ( ! $tagFound->hasAttributes() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$linkTagParts = array();
|
||||
$linkTagParts[] = '<link ';
|
||||
|
||||
foreach ($tagFound->attributes as $attr) {
|
||||
$attrName = $attr->nodeName;
|
||||
$attrValue = $attr->nodeValue;
|
||||
|
||||
if ($attrName) {
|
||||
if ($attrValue !== '') {
|
||||
$linkTagParts[] = '(\s+|)' . preg_quote($attrName, '/') . '(\s+|)=(\s+|)(|"|\')' . preg_quote($attrValue, '/') . '(|"|\')(|\s+)';
|
||||
} else {
|
||||
$linkTagParts[] = '(\s+|)' . preg_quote($attrName, '/') . '(|((\s+|)=(\s+|)(|"|\')(|"|\')))';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$linkTagParts[] = '(|\s+)(|/)>';
|
||||
|
||||
$linkTagFinalRegExPart = implode('', $linkTagParts);
|
||||
|
||||
preg_match_all(
|
||||
'#'.$linkTagFinalRegExPart.'#Umi',
|
||||
$htmlSource,
|
||||
$matchSourceFromTag,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
// It always has to be a match from the DOM generated tag
|
||||
// Otherwise, default it to RegEx
|
||||
if ( empty($matchSourceFromTag) || ! (isset($matchSourceFromTag[0][0]) && ! empty($matchSourceFromTag[0][0])) ) {
|
||||
$stickToRegEx = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$matchesSourcesFromTags[] = array('link_tag' => $matchSourceFromTag[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! $stickToRegEx) {
|
||||
$shaOneToOriginal = array();
|
||||
|
||||
$htmlSourceAltEncoded = $htmlSourceAlt;
|
||||
|
||||
foreach($domTagQuery as $tagFound) {
|
||||
if ( $tagFound->nodeValue && in_array( $tagFound->nodeName, array( 'style', 'script', 'noscript' ) ) ) {
|
||||
if (strpos($htmlSourceAlt, $tagFound->nodeValue) === false) {
|
||||
$stickToRegEx = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$shaOneToOriginal[sha1($tagFound->nodeValue)] = $tagFound->nodeValue;
|
||||
|
||||
$htmlSourceAltEncoded = str_replace(
|
||||
$tagFound->nodeValue,
|
||||
'/*[wpacu]*/' . sha1($tagFound->nodeValue) . '/*[/wpacu]*/',
|
||||
$htmlSourceAltEncoded
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$domDocForTwo = Misc::initDOMDocument();
|
||||
|
||||
$domDocForTwo->loadHTML($htmlSourceAltEncoded);
|
||||
|
||||
$selectorTwo = new \DOMXPath($domDocForTwo);
|
||||
|
||||
$domTagQueryTwo = $selectorTwo->query('//style|//script|//noscript');
|
||||
|
||||
foreach($domTagQueryTwo as $tagFoundTwo) {
|
||||
$tagType = in_array($tagFoundTwo->nodeName, array('link', 'style')) ? 'css' : 'js';
|
||||
|
||||
if ( $tagFoundTwo->hasAttributes() ) {
|
||||
foreach ( $tagFoundTwo->attributes as $attr ) {
|
||||
if ( self::skipTagIfNotRelevant( $attr->nodeName, 'attribute', $tagType ) ) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tagParts = array();
|
||||
$tagParts[] = '<'.$tagFoundTwo->nodeName;
|
||||
|
||||
foreach ($tagFoundTwo->attributes as $attr) {
|
||||
$attrName = $attr->nodeName;
|
||||
$attrValue = $attr->nodeValue;
|
||||
|
||||
if ($attrName) {
|
||||
if ($attrValue !== '') {
|
||||
$tagParts[] = '(\s+|)' . preg_quote($attrName, '/') . '(\s+|)=(\s+|)(|"|\')' . preg_quote($attrValue, '/') . '(|"|\')(|\s+)';
|
||||
} else {
|
||||
$tagParts[] = '(\s+|)' . preg_quote($attrName, '/') . '(|((\s+|)=(\s+|)(|"|\')(|"|\')))';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tagParts[] = '(|\s+)>';
|
||||
|
||||
if ($tagFoundTwo->nodeValue) {
|
||||
$tagParts[] = preg_quote($tagFoundTwo->nodeValue, '/');
|
||||
}
|
||||
|
||||
$tagParts[] = '</'.$tagFoundTwo->nodeName.'>';
|
||||
|
||||
$tagFinalRegExPart = implode('', $tagParts);
|
||||
|
||||
preg_match_all(
|
||||
'#'.$tagFinalRegExPart.'#Umi',
|
||||
$htmlSourceAltEncoded,
|
||||
$matchSourceFromTagTwo,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
// It always has to be a match from the DOM generated tag
|
||||
// Otherwise, default it to RegEx
|
||||
if ( empty($matchSourceFromTagTwo) || ! (isset($matchSourceFromTagTwo[0][0]) && ! empty($matchSourceFromTagTwo[0][0])) ) {
|
||||
$stickToRegEx = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$encodedNodeValue = Misc::extractBetween($matchSourceFromTagTwo[0][0], '/*[wpacu]*/', '/*[/wpacu]*/');
|
||||
|
||||
$matchedTag = str_replace('/*[wpacu]*/'.$encodedNodeValue.'/*[/wpacu]*/', $shaOneToOriginal[$encodedNodeValue], $matchSourceFromTagTwo[0][0]);
|
||||
|
||||
$tagTypeForReference = ($tagFoundTwo->nodeName === 'style') ? 'style_tag' : 'script_noscript_tag';
|
||||
|
||||
$matchesSourcesFromTags[] = array($tagTypeForReference => $matchedTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [START] Collect Hardcoded LINK (stylesheet) & STYLE tags
|
||||
*/
|
||||
if ($stickToRegEx || ! Misc::isDOMDocumentOn()) {
|
||||
preg_match_all(
|
||||
'#(?=(?P<link_tag><link[^>]*stylesheet[^>]*(>)))|(?=(?P<style_tag><style[^>]*?>.*</style>))#Umsi',
|
||||
$htmlSourceAlt,
|
||||
$matchesSourcesFromTags,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $matchesSourcesFromTags ) ) {
|
||||
// Only the hashes are set
|
||||
// For instance, 'd1eae32c4e99d24573042dfbb71f5258a86e2a8e' is the hash for the following script:
|
||||
/*
|
||||
* <style media="print">#wpadminbar { display:none; }</style>
|
||||
*/
|
||||
$stripsSpecificStylesHashes = array(
|
||||
'5ead5f033961f3b8db362d2ede500051f659dd6d',
|
||||
'25bd090513716c34b48b0495c834d2070088ad24'
|
||||
);
|
||||
|
||||
// Sometimes, the hash checking might fail (if there's a small change to the JS content)
|
||||
// Consider using a fallback verification by checking the actual content
|
||||
$stripsSpecificStylesContaining = array(
|
||||
'<style media="print">#wpadminbar { display:none; }</style>',
|
||||
'id="edd-store-menu-styling"',
|
||||
'#wp-admin-bar-gform-forms'
|
||||
);
|
||||
|
||||
foreach ( $matchesSourcesFromTags as $matchedTag ) {
|
||||
// LINK "stylesheet" tags (if any)
|
||||
if ( isset( $matchedTag['link_tag'] ) && trim( $matchedTag['link_tag'] ) !== '' && ( trim( strip_tags( $matchedTag['link_tag'] ) ) === '' ) ) {
|
||||
$matchedTagOutput = trim( $matchedTag['link_tag'] );
|
||||
|
||||
// Own plugin assets and enqueued ones since they aren't hardcoded
|
||||
if (self::skipTagIfNotRelevant($matchedTagOutput)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hardCodedAssets['link_and_style_tags'][] = $matchedTagOutput;
|
||||
}
|
||||
|
||||
// STYLE inline tags (if any)
|
||||
if ( isset( $matchedTag['style_tag'] ) && trim( $matchedTag['style_tag'] ) !== '' ) {
|
||||
$matchedTagOutput = trim( $matchedTag['style_tag'] );
|
||||
|
||||
/*
|
||||
* Strip certain STYLE tags irrelevant for the list (e.g. related to the WordPress Admin Bar, etc.)
|
||||
*/
|
||||
if ( in_array( self::determineHardcodedAssetSha1( $matchedTagOutput ), $stripsSpecificStylesHashes ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $stripsSpecificStylesContaining as $cssContentTargeted ) {
|
||||
if ( strpos( $matchedTagOutput, $cssContentTargeted ) !== false ) {
|
||||
continue 2; // applies for this "foreach": ($matchesSourcesFromTags as $matchedTag)
|
||||
}
|
||||
}
|
||||
|
||||
// Own plugin assets and enqueued ones since they aren't hardcoded
|
||||
if (self::skipTagIfNotRelevant($matchedTagOutput)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( wp_styles()->done as $cssHandle ) {
|
||||
if ( strpos( $matchedTagOutput,
|
||||
'<style id=\'' . trim( $cssHandle ) . '-inline-css\'' ) !== false ) {
|
||||
// Do not consider the STYLE added via WordPress with wp_add_inline_style() as it's not hardcoded
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$hardCodedAssets['link_and_style_tags'][] = $matchedTagOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* [END] Collect Hardcoded LINK (stylesheet) & STYLE tags
|
||||
*/
|
||||
}
|
||||
|
||||
if ($collectScripts) {
|
||||
/*
|
||||
* [START] Collect Hardcoded SCRIPT (src/inline)
|
||||
*/
|
||||
if ($stickToRegEx || ! Misc::isDOMDocumentOn()) {
|
||||
preg_match_all( '@<script[^>]*?>.*?</script>|<noscript[^>]*?>.*?</noscript>@si', $htmlSourceAlt, $matchesScriptTags, PREG_SET_ORDER );
|
||||
} else {
|
||||
$matchesScriptTags = array();
|
||||
|
||||
if (! empty($matchesSourcesFromTags)) {
|
||||
foreach ($matchesSourcesFromTags as $matchedTag) {
|
||||
if (isset($matchedTag['script_noscript_tag']) && $matchedTag['script_noscript_tag']) {
|
||||
$matchesScriptTags[][0] = $matchedTag['script_noscript_tag'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allInlineAssocWithJsHandle = array();
|
||||
|
||||
if ( isset( wp_scripts()->done ) && ! empty( wp_scripts()->done ) ) {
|
||||
foreach ( wp_scripts()->done as $assetHandle ) {
|
||||
// Now, go through the list of inline SCRIPTs associated with an enqueued SCRIPT (with "src" attribute)
|
||||
// And make sure they do not show to the hardcoded list, since they are related to the handle, and they are stripped when the handle is dequeued
|
||||
$anyInlineAssocWithJsHandle = OptimizeJs::getInlineAssociatedWithScriptHandle( $assetHandle, wp_scripts()->registered, 'handle' );
|
||||
if ( ! empty( $anyInlineAssocWithJsHandle ) ) {
|
||||
foreach ( $anyInlineAssocWithJsHandle as $jsInlineTagContent ) {
|
||||
if ( trim( $jsInlineTagContent ) === '' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$allInlineAssocWithJsHandle[] = trim($jsInlineTagContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allInlineAssocWithJsHandle = array_unique($allInlineAssocWithJsHandle);
|
||||
}
|
||||
|
||||
// Go through the hardcoded SCRIPT tags
|
||||
if ( isset( $matchesScriptTags ) && ! empty( $matchesScriptTags ) ) {
|
||||
// Only the hashes are set
|
||||
// For instance, 'd1eae32c4e99d24573042dfbb71f5258a86e2a8e' is the hash for the following script:
|
||||
/*
|
||||
* <script>
|
||||
(function() {
|
||||
var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
|
||||
request = true;
|
||||
b[c] = b[c].replace( rcs, ' ' );
|
||||
// The customizer requires postMessage and CORS (if the site is cross domain)
|
||||
b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
|
||||
}());
|
||||
</script>
|
||||
*/
|
||||
$stripsSpecificScriptsHashes = array(
|
||||
'd1eae32c4e99d24573042dfbb71f5258a86e2a8e',
|
||||
'1a8f46f9f33e5d95919620df54781acbfa9efff7'
|
||||
);
|
||||
|
||||
// Sometimes, the hash checking might fail (if there's a small change to the JS content)
|
||||
// Consider using a fallback verification by checking the actual content
|
||||
$stripsSpecificScriptsContaining = array(
|
||||
'// The customizer requires postMessage and CORS (if the site is cross domain)',
|
||||
'b[c] += ( window.postMessage && request ? \' \' : \' no-\' ) + cs;',
|
||||
"(function(){var request,b=document.body,c='className',cs='customize-support',rcs=new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');request=!0;b[c]=b[c].replace(rcs,' ');b[c]+=(window.postMessage&&request?' ':' no-')+cs}())",
|
||||
'document.body.className = document.body.className.replace( /(^|\s)(no-)?customize-support(?=\s|$)/, \'\' ) + \' no-customize-support\'',
|
||||
"c = c.replace(/woocommerce-no-js/, 'woocommerce-js');" // WooCommerce related
|
||||
);
|
||||
|
||||
foreach ( $matchesScriptTags as $matchedTag ) {
|
||||
if ( isset( $matchedTag[0] ) && $matchedTag[0]
|
||||
&& (stripos( $matchedTag[0], '<script' ) === 0 || stripos( $matchedTag[0], '<noscript' ) === 0) ) {
|
||||
$matchedTagOutput = trim( $matchedTag[0] );
|
||||
|
||||
// Own plugin assets and enqueued ones since they aren't hardcoded
|
||||
if (self::skipTagIfNotRelevant($matchedTagOutput, 'whole_tag', 'js', array('all_inline_assoc_with_js_handle' => $allInlineAssocWithJsHandle))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip certain SCRIPT tags irrelevant for the list (e.g. related to WordPress Customiser, Admin Bar, etc.)
|
||||
*/
|
||||
if ( in_array( self::determineHardcodedAssetSha1( $matchedTagOutput ), $stripsSpecificScriptsHashes ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $stripsSpecificScriptsContaining as $jsContentTargeted ) {
|
||||
if ( strpos( $matchedTagOutput, $jsContentTargeted ) !== false ) {
|
||||
continue 2; // applies for this "foreach": ($matchesScriptTags as $matchedTag)
|
||||
}
|
||||
}
|
||||
|
||||
$hardCodedAssets['script_src_or_inline_and_noscript_inline_tags'][] = trim( $matchedTag[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* [END] Collect Hardcoded SCRIPT (src/inline)
|
||||
*/
|
||||
}
|
||||
|
||||
if ($stickToRegEx && ! empty($hardCodedAssets['link_and_style_tags']) && ! empty($hardCodedAssets['script_src_or_inline_and_noscript_inline_tags'])) {
|
||||
$hardCodedAssets = self::removeAnyLinkTagsThatMightBeDetectedWithinScriptTags( $hardCodedAssets );
|
||||
}
|
||||
|
||||
$tagsWithinConditionalComments = self::extractHtmlFromConditionalComments( $htmlSourceAlt );
|
||||
|
||||
if (Main::instance()->isGetAssetsCall) {
|
||||
// AJAX call within the Dashboard
|
||||
$hardCodedAssets['within_conditional_comments'] = $tagsWithinConditionalComments;
|
||||
}
|
||||
|
||||
if ($encodeIt) {
|
||||
return base64_encode( wp_json_encode( $hardCodedAssets ) );
|
||||
}
|
||||
|
||||
return $hardCodedAssets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param $via ('whole_tag', 'attribute')
|
||||
* @param string $type ('css', 'js')
|
||||
* @param array $extras ('all_inline_assoc_with_js_handle')
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function skipTagIfNotRelevant($value, $via = 'whole_tag', $type = 'css', $extras = array())
|
||||
{
|
||||
if ($via === 'whole_tag') {
|
||||
if ($type === 'css') {
|
||||
if ( strpos( $value, 'data-wpacu-style-handle=' ) !== false ) {
|
||||
// skip the SCRIPT with src that was enqueued properly and keep the hardcoded ones
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ( strpos( $value, 'data-wpacu-own-inline-style=' ) !== false ) ||
|
||||
( strpos( $value, 'data-wpacu-inline-css-file=' ) !== false ) ) {
|
||||
// remove plugin's own STYLE tags as they are not relevant in this context
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do not add to the list elements such as Emojis (not relevant for hard-coded tags)
|
||||
if ( strpos( $value, 'img.wp-smiley' ) !== false
|
||||
&& strpos( $value, 'img.emoji' ) !== false
|
||||
&& strpos( $value, '!important;' ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($type === 'js') {
|
||||
if ( strpos( $value, 'data-wpacu-script-handle=' ) !== false ) {
|
||||
// skip the SCRIPT with src that was enqueued properly and keep the hardcoded ones
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ( strpos( $value, 'data-wpacu-own-inline-script=' ) !== false ) ||
|
||||
( strpos( $value, 'data-wpacu-inline-js-file=' ) !== false ) ) {
|
||||
// skip plugin's own SCRIPT tags as they are not relevant in this context
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( strpos( $value, 'wpacu-preload-async-css-fallback' ) !== false ) {
|
||||
// skip plugin's own SCRIPT tags as they are not relevant in this context
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( strpos( $value, 'window._wpemojiSettings' ) !== false
|
||||
&& strpos( $value, 'twemoji' ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the type and only allow SCRIPT tags with type='text/javascript' or no type at all (it will default to 'text/javascript')
|
||||
$matchedTagInner = strip_tags( $value );
|
||||
$matchedTagOnlyTags = str_replace( $matchedTagInner, '', $value );
|
||||
|
||||
$scriptType = Misc::getValueFromTag($matchedTagOnlyTags, 'type') ?: 'text/javascript';
|
||||
|
||||
if ( strpos( $scriptType, 'text/javascript' ) === false ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$allInlineAssocWithJsHandle = isset($extras['all_inline_assoc_with_js_handle']) ? $extras['all_inline_assoc_with_js_handle'] : array();
|
||||
|
||||
$hasSrc = false;
|
||||
|
||||
if (strpos($matchedTagOnlyTags, ' src=') !== false) {
|
||||
$hasSrc = true;
|
||||
}
|
||||
|
||||
if ( ! $hasSrc && ! empty( $allInlineAssocWithJsHandle ) ) {
|
||||
preg_match_all("'<script[^>]*?>(.*?)</script>'si", $value, $matchesFromTagOutput);
|
||||
$matchedTagOutputInner = isset($matchesFromTagOutput[1][0]) && trim($matchesFromTagOutput[1][0])
|
||||
? trim($matchesFromTagOutput[1][0]) : false;
|
||||
|
||||
$matchedTagOutputInnerCleaner = $matchedTagOutputInner;
|
||||
|
||||
$stripStrStart = '/* <![CDATA[ */';
|
||||
$stripStrEnd = '/* ]]> */';
|
||||
|
||||
if (strpos($matchedTagOutputInnerCleaner, $stripStrStart) === 0
|
||||
&& Misc::endsWith($matchedTagOutputInnerCleaner, '/* ]]> */')) {
|
||||
$matchedTagOutputInnerCleaner = substr($matchedTagOutputInnerCleaner, strlen($stripStrStart));
|
||||
$matchedTagOutputInnerCleaner = substr($matchedTagOutputInnerCleaner, 0, -strlen($stripStrEnd));
|
||||
$matchedTagOutputInnerCleaner = trim($matchedTagOutputInnerCleaner);
|
||||
}
|
||||
|
||||
if (in_array($matchedTagOutputInnerCleaner, $allInlineAssocWithJsHandle)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($via === 'attribute') {
|
||||
if ( $type === 'css' ) {
|
||||
$possibleSignatures = array(
|
||||
'data-wpacu-style-handle',
|
||||
'data-wpacu-own-inline-style',
|
||||
'data-wpacu-inline-css-file'
|
||||
);
|
||||
} else {
|
||||
$possibleSignatures = array(
|
||||
'data-wpacu-script-handle',
|
||||
'data-wpacu-own-inline-script',
|
||||
'data-wpacu-inline-js-file',
|
||||
'wpacu-preload-async-css-fallback'
|
||||
);
|
||||
}
|
||||
|
||||
if (in_array($value, $possibleSignatures)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // default
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $hardcodedAssets
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function removeAnyLinkTagsThatMightBeDetectedWithinScriptTags($hardcodedAssets)
|
||||
{
|
||||
foreach ($hardcodedAssets['link_and_style_tags'] as $cssTagIndex => $cssTag) {
|
||||
if ($cssTag) {
|
||||
foreach ($hardcodedAssets['script_src_or_inline_and_noscript_inline_tags'] as $scriptTag) {
|
||||
if (strpos($scriptTag, $cssTag) !== false) {
|
||||
// e.g. could be '<script>var linkToCss="<link href='[path_to_custom_css_file_here]'>";</script>'
|
||||
unset($hardcodedAssets['link_and_style_tags'][$cssTagIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $hardcodedAssets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function extractHtmlFromConditionalComments($htmlSource)
|
||||
{
|
||||
preg_match_all('#<!--\[if(.*?)]>(<!-->|-->|\s|)(.*?)(<!--<!|<!)\[endif]-->#si', $htmlSource, $matchedContent);
|
||||
|
||||
if (isset($matchedContent[1], $matchedContent[3]) && ! empty($matchedContent[1]) && ! empty($matchedContent[3])) {
|
||||
$conditions = array_map('trim', $matchedContent[1]);
|
||||
$tags = array_map('trim', $matchedContent[3]);
|
||||
|
||||
return array(
|
||||
'conditions' => $conditions,
|
||||
'tags' => $tags,
|
||||
);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $targetedTag
|
||||
* @param $contentWithinConditionalComments
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isWithinConditionalComment($targetedTag, $contentWithinConditionalComments)
|
||||
{
|
||||
if (empty($contentWithinConditionalComments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$targetedTag = trim($targetedTag);
|
||||
|
||||
foreach ($contentWithinConditionalComments['tags'] as $tagIndex => $tagFromList) {
|
||||
$tagFromList = trim($tagFromList);
|
||||
|
||||
if ($targetedTag === $tagFromList || strpos($targetedTag, $tagFromList) !== false) {
|
||||
return $contentWithinConditionalComments['conditions'][$tagIndex]; // Stops here and returns the condition
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Not within a conditional comment (most cases)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlTag
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function belongsTo($htmlTag)
|
||||
{
|
||||
$belongList = array(
|
||||
'wpcf7recaptcha.' => '"Contact Form 7" plugin',
|
||||
'c = c.replace(/woocommerce-no-js/, \'woocommerce-js\');' => '"WooCommerce" plugin',
|
||||
'.woocommerce-product-gallery{ opacity: 1 !important; }' => '"WooCommerce" plugin',
|
||||
'-ss-slider-3' => '"Smart Slider 3" plugin',
|
||||
'N2R(["nextend-frontend","smartslider-frontend","smartslider-simple-type-frontend"]' => '"Smart Slider 3" plugin',
|
||||
'function setREVStartSize' => '"Slider Revolution" plugin',
|
||||
'jQuery(\'.rev_slider_wrapper\')' => '"Slider Revolution" plugin',
|
||||
'jQuery(\'#wp-admin-bar-revslider-default' => '"Slider Revolution" plugin'
|
||||
);
|
||||
|
||||
foreach ($belongList as $ifContains => $isFromSource) {
|
||||
if ( strpos( $htmlTag, $ifContains) !== false ) {
|
||||
return $isFromSource;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tagOutput
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function determineHardcodedAssetSha1($tagOutput)
|
||||
{
|
||||
// Look if the "href" or "src" ends with '.css' or '.js'
|
||||
// Only hash the actual path to the file
|
||||
// In case the tag changes (e.g. an attribute will be added), the tag will be considered the same for the plugin rules
|
||||
// To avoid the rules from not working / e.g. the file could have a dynamic "?ver=" at the end
|
||||
if ( ! (stripos($tagOutput, '<link') !== false || stripos($tagOutput, '<style') !== false
|
||||
|| stripos($tagOutput, '<script') !== false || stripos($tagOutput, '<noscript') !== false) ) {
|
||||
return sha1( $tagOutput ); // default
|
||||
}
|
||||
|
||||
$isLinkWithHref = (stripos($tagOutput, '<link') !== false) && preg_match('#href(\s+|)=(\s+|)(["\'])(.*)(["\'])#Usmi', $tagOutput);
|
||||
$isScriptWithSrc = (stripos($tagOutput, '<script') !== false) && preg_match('#src(\s+|)=(\s+|)(["\'])(.*)(["\'])|src(\s+|)=(\s+|)(.*)(\s+)#Usmi', $tagOutput);
|
||||
|
||||
if ($isLinkWithHref || $isScriptWithSrc) {
|
||||
return self::determineHardcodedAssetSha1ForAssetsWithSource($tagOutput);
|
||||
}
|
||||
|
||||
if (stripos($tagOutput, '<style') !== false || stripos($tagOutput, '<script') !== false || stripos($tagOutput, '<noscript') !== false) {
|
||||
return self::determineHardcodedAssetSha1ForAssetsWithoutSource($tagOutput);
|
||||
}
|
||||
|
||||
return sha1( $tagOutput ); // default
|
||||
}
|
||||
|
||||
/**
|
||||
// In case there are STYLE tags and SCRIPT tags without any SRC, make sure to consider only the content of the tag as a reference
|
||||
// e.g. if the user updates <style type="text/css"> to <style> the tag should be considered the same if the content is the same
|
||||
// also, do not consider any whitespaces from the beginning and ending of the tag's content
|
||||
*
|
||||
* @param $tagOutput
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function determineHardcodedAssetSha1ForAssetsWithoutSource($tagOutput)
|
||||
{
|
||||
if (stripos($tagOutput, '<style') !== false) {
|
||||
preg_match_all('@(<style[^>]*?>)(.*?)</style>@si', $tagOutput, $matches);
|
||||
|
||||
if (isset($matches[0][0], $matches[2][0]) && strlen($tagOutput) === strlen($matches[0][0])) {
|
||||
return sha1( trim($matches[2][0]) ); // the hashed content of the STYLE tag
|
||||
}
|
||||
} elseif (stripos($tagOutput, '<script') !== false) {
|
||||
preg_match_all('@(<script[^>]*?>)(.*?)</script>@si', $tagOutput, $matches);
|
||||
|
||||
if (isset($matches[0][0], $matches[2][0]) && strlen($tagOutput) === strlen($matches[0][0])) {
|
||||
return sha1( trim($matches[2][0]) ); // the hashed content of the SCRIPT tag
|
||||
}
|
||||
} elseif (stripos($tagOutput, '<noscript') !== false) {
|
||||
preg_match_all('@(<noscript[^>]*?>)(.*?)</noscript>@si', $tagOutput, $matches);
|
||||
|
||||
if (isset($matches[0][0], $matches[2][0]) && strlen($tagOutput) === strlen($matches[0][0])) {
|
||||
return sha1( trim($matches[2][0]) ); // the hashed content of the NOSCRIPT tag
|
||||
}
|
||||
}
|
||||
|
||||
return sha1($tagOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only the LINK tags and SCRIPT tags with the "href" and "src" attributes would be considered
|
||||
*
|
||||
* @param $tagOutput
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function determineHardcodedAssetSha1ForAssetsWithSource($tagOutput)
|
||||
{
|
||||
if ($finalCleanSource = self::getRelSourceFromTagOutputForReference($tagOutput)) {
|
||||
return sha1($finalCleanSource);
|
||||
}
|
||||
|
||||
return sha1( $tagOutput ); // default
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tagOutput
|
||||
*
|
||||
* @return array|false|string|string[]
|
||||
*/
|
||||
public static function getRelSourceFromTagOutputForReference($tagOutput)
|
||||
{
|
||||
if (stripos($tagOutput, 'href') !== false && stripos($tagOutput, 'stylesheet') !== false && stripos(trim($tagOutput), '<link') === 0) {
|
||||
$attrToGet = 'href';
|
||||
$extToCheck = 'css';
|
||||
} else {
|
||||
$attrToGet = 'src';
|
||||
$extToCheck = 'js';
|
||||
}
|
||||
|
||||
$sourceValue = Misc::getValueFromTag($tagOutput, $attrToGet);
|
||||
|
||||
if (! $sourceValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( stripos( $sourceValue, '.' . $extToCheck . '?' ) !== false ) {
|
||||
list( $cleanSource ) = explode( '.' . $extToCheck . '?', $sourceValue );
|
||||
$finalCleanSource = $cleanSource . '.' . $extToCheck;
|
||||
} else {
|
||||
$finalCleanSource = $sourceValue;
|
||||
}
|
||||
|
||||
if ( $finalCleanSource ) {
|
||||
$localAssetPath = OptimizeCommon::getLocalAssetPath( $finalCleanSource, $extToCheck );
|
||||
|
||||
if ( $localAssetPath ) {
|
||||
$sourceRelPath = OptimizeCommon::getSourceRelPath( $finalCleanSource );
|
||||
|
||||
if ( $sourceRelPath ) {
|
||||
return $finalCleanSource;
|
||||
}
|
||||
} else {
|
||||
$finalCleanSource = str_ireplace( array( 'http://', 'https://' ), '', $finalCleanSource );
|
||||
$finalCleanSource = ( strpos( $finalCleanSource, '//' ) === 0 ) ? substr( $finalCleanSource, 2 ) : $finalCleanSource; // if the string starts with '//', remove it
|
||||
}
|
||||
}
|
||||
|
||||
return $finalCleanSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHardCodedManageAreaForFrontEndView($data)
|
||||
{
|
||||
$dataSettingsFrontEnd = ObjectCache::wpacu_cache_get('wpacu_settings_frontend_data') ?: array();
|
||||
$dataSettingsFrontEnd['page_unload_text'] = esc_html($data['page_unload_text']);
|
||||
// The following string will be replaced by the values got from the AJAX call to /?wpassetcleanup_load=1&wpacu_just_hardcoded
|
||||
$dataWpacuSettingsFrontend = base64_encode(wp_json_encode($dataSettingsFrontEnd));
|
||||
|
||||
$currentHardcodedAssetRules = '';
|
||||
|
||||
// When the form is submitted it will clear some values if they are not sent anymore which can happen with a failed AJAX call to retrieve the list of hardcoded assets
|
||||
// Place the current values to the area in case the AJAX call fails, and it won't print the list
|
||||
// If the user presses "Update", it won't clear any existing rules
|
||||
// If the list is printed, obviously it will be with all the fields in place as they should be
|
||||
foreach (array('current_unloaded_page_level', 'load_exceptions', 'handle_unload_regex', 'handle_load_regex', 'handle_load_logged_in') as $ruleKey) {
|
||||
foreach ( array( 'styles', 'scripts' ) as $assetType ) {
|
||||
if ( isset( $dataSettingsFrontEnd[$ruleKey][ $assetType ] ) && ! empty( $dataSettingsFrontEnd[$ruleKey][$assetType] ) ) {
|
||||
// Go through the values, depending on how the array is structured
|
||||
// handle_unload_regex, handle_load_regex
|
||||
if (in_array($ruleKey, array('handle_unload_regex', 'handle_load_regex'))) {
|
||||
foreach ( $dataSettingsFrontEnd[ $ruleKey ][ $assetType ] as $assetHandle => $assetValues ) {
|
||||
if ( strpos( $assetHandle, 'wpacu_hardcoded_' ) !== false ) {
|
||||
if ($ruleKey === 'handle_unload_regex') {
|
||||
$enableValue = isset( $assetValues['enable'] ) ? $assetValues['enable'] : '';
|
||||
$regExValue = isset( $assetValues['value'] ) ? $assetValues['value'] : '';
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_handle_unload_regex[' . $assetType . '][' . $assetHandle . '][enable]" value="' . $enableValue . '" />';
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_handle_unload_regex[' . $assetType . '][' . $assetHandle . '][value]" value="' . esc_attr( $regExValue ) . '" />';
|
||||
} elseif ($ruleKey === 'handle_load_regex') {
|
||||
$enableValue = isset( $assetValues['enable'] ) ? $assetValues['enable'] : '';
|
||||
$regExValue = isset( $assetValues['value'] ) ? $assetValues['value'] : '';
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_handle_load_regex[' . $assetType . '][' . $assetHandle . '][enable]" value="' . $enableValue . '" />';
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_handle_load_regex[' . $assetType . '][' . $assetHandle . '][value]" value="' . esc_attr( $regExValue ) . '" />';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// current unloaded on a page level, load_exceptions, handle_load_logged_in
|
||||
foreach ( $dataSettingsFrontEnd[ $ruleKey ][ $assetType ] as $assetHandle ) {
|
||||
if ( strpos( $assetHandle, 'wpacu_hardcoded_' ) !== false ) {
|
||||
if ( $ruleKey === 'current_unloaded_page_level' ) {
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpassetcleanup[' . $assetType . '][]" value="' . $assetHandle . '" />';
|
||||
} elseif ( $ruleKey === 'load_exceptions' ) {
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_styles_load_it[]" value="' . $assetHandle . '" />';
|
||||
} elseif ($ruleKey === 'handle_load_logged_in') {
|
||||
$currentHardcodedAssetRules .= '<input type="hidden" name="wpacu_load_it_logged_in['.$assetType.']['.$assetHandle.']" value="1" />';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="wpacu-assets-collapsible-wrap wpacu-wrap-area wpacu-hardcoded" id="wpacu-assets-collapsible-wrap-hardcoded-list" data-wpacu-settings-frontend="'.esc_attr($dataWpacuSettingsFrontend).'">
|
||||
<a class="wpacu-assets-collapsible wpacu-assets-collapsible-active" href="#" style="padding: 15px 15px 15px 44px;"><span class="dashicons dashicons-code-standards"></span> Hardcoded (non-enqueued) Styles & Scripts</a>
|
||||
<div class="wpacu-assets-collapsible-content" style="max-height: inherit;">
|
||||
<div style="padding: 20px 0; margin: 0;"><img src="'.esc_url(admin_url('images/spinner.gif')).'" align="top" width="20" height="20" alt="" /> The list of hardcoded assets is fetched... Please wait...</div>
|
||||
'.wp_kses($currentHardcodedAssetRules, array('input' => array('type' => array(), 'name' => array(), 'value' => array()))).'
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
}
|
326
wp-content/plugins/wp-asset-clean-up/classes/ImportExport.php
Normal file
326
wp-content/plugins/wp-asset-clean-up/classes/ImportExport.php
Normal file
@ -0,0 +1,326 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
|
||||
/**
|
||||
* Class ImportExport
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class ImportExport
|
||||
{
|
||||
/***** BEGIN EXPORT ******/
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function jsonSettings()
|
||||
{
|
||||
$wpacuSettings = new Settings();
|
||||
$settingsArray = $wpacuSettings->getAll();
|
||||
|
||||
// Some "Site-wide Common Unloads" values are fetched outside the "Settings" option values
|
||||
// e.g. jQuery Migrate, Comment Reply
|
||||
$globalUnloadList = Main::instance()->getGlobalUnload();
|
||||
|
||||
// CSS
|
||||
$settingsArray['disable_dashicons_for_guests'] = in_array( 'dashicons', $globalUnloadList['styles'] );
|
||||
$settingsArray['disable_wp_block_library'] = in_array( 'wp-block-library', $globalUnloadList['styles'] );
|
||||
|
||||
// JS
|
||||
$settingsArray['disable_jquery_migrate'] = in_array( 'jquery-migrate', $globalUnloadList['scripts'] );
|
||||
$settingsArray['disable_comment_reply'] = in_array( 'comment-reply', $globalUnloadList['scripts'] );
|
||||
|
||||
return wp_json_encode($settingsArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the "Export" button clicked? Do verifications and send the right headers
|
||||
*/
|
||||
public function doExport()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! Misc::getVar('post', 'wpacu_do_export_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpacuExportFor = Misc::getVar('post', 'wpacu_export_for');
|
||||
|
||||
if (! $wpacuExportFor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Last important check
|
||||
\check_admin_referer('wpacu_do_export', 'wpacu_do_export_nonce');
|
||||
|
||||
$exportComment = 'Exported [exported_text] via '.WPACU_PLUGIN_TITLE.' (v'.WPACU_PLUGIN_VERSION.') - Timestamp: '.time();
|
||||
|
||||
// "Settings" values (could be just default ones if none are found in the database)
|
||||
if ($wpacuExportFor === 'settings') {
|
||||
$exportComment = str_replace('[exported_text]', 'Settings', $exportComment);
|
||||
|
||||
$settingsJson = $this->jsonSettings();
|
||||
|
||||
$valuesArray = array(
|
||||
'__comment' => $exportComment,
|
||||
'settings' => json_decode($settingsJson, ARRAY_A)
|
||||
);
|
||||
}
|
||||
|
||||
if ($wpacuExportFor === 'everything') {
|
||||
$exportComment = str_replace('[exported_text]', 'Everything', $exportComment);
|
||||
|
||||
// "Settings"
|
||||
$settingsJson = $this->jsonSettings();
|
||||
|
||||
// "Homepage"
|
||||
$frontPageNoLoad = get_option(WPACU_PLUGIN_ID . '_front_page_no_load');
|
||||
$frontPageNoLoadArray = json_decode($frontPageNoLoad, ARRAY_A);
|
||||
|
||||
$frontPageExceptionsListJson = get_option(WPACU_PLUGIN_ID . '_front_page_load_exceptions');
|
||||
$frontPageExceptionsListArray = json_decode($frontPageExceptionsListJson, ARRAY_A);
|
||||
|
||||
// "Site-wide" Unloads
|
||||
$globalUnloadListJson = get_option(WPACU_PLUGIN_ID . '_global_unload');
|
||||
$globalUnloadArray = json_decode($globalUnloadListJson, ARRAY_A);
|
||||
|
||||
// "Bulk" unloads (for all pages, posts, custom post type)
|
||||
$bulkUnloadListJson = get_option(WPACU_PLUGIN_ID . '_bulk_unload');
|
||||
$bulkUnloadArray = json_decode($bulkUnloadListJson, ARRAY_A);
|
||||
|
||||
// Post type: load exceptions
|
||||
$postTypeLoadExceptionsJson = get_option(WPACU_PLUGIN_ID . '_post_type_load_exceptions');
|
||||
$postTypeLoadExceptionsArray = json_decode($postTypeLoadExceptionsJson, ARRAY_A);
|
||||
|
||||
$globalDataListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
$globalDataListArray = json_decode($globalDataListJson, ARRAY_A);
|
||||
|
||||
// [wpacu_pro]
|
||||
// Load exceptions for extras: is_archive(), author, search, 404 pages
|
||||
$extrasLoadExceptionsListJson = get_option(WPACU_PLUGIN_ID . '_extras_load_exceptions');
|
||||
$extrasLoadExceptionsArray = json_decode($extrasLoadExceptionsListJson, ARRAY_A);
|
||||
|
||||
// Load exceptions for pages that have certain taxonomies set
|
||||
$postTypeViaTaxLoadExceptionsJson = get_option(WPACU_PLUGIN_ID . '_post_type_via_tax_load_exceptions');
|
||||
$postTypeViaTaxLoadExceptionsArray = json_decode($postTypeViaTaxLoadExceptionsJson, ARRAY_A);
|
||||
// [/wpacu_pro]
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$allMetaResults = array();
|
||||
|
||||
$metaKeyLike = '_' . WPACU_PLUGIN_ID . '_%';
|
||||
|
||||
$tableList = array($wpdb->postmeta);
|
||||
|
||||
foreach ($tableList as $tableName) {
|
||||
if ( $tableName === $wpdb->postmeta ) {
|
||||
$sqlFetchPostsMetas = <<<SQL
|
||||
SELECT post_id, meta_key, meta_value FROM `{$wpdb->postmeta}` WHERE meta_key LIKE '{$metaKeyLike}'
|
||||
SQL;
|
||||
$allMetaResults['postmeta'] = $wpdb->get_results( $sqlFetchPostsMetas, ARRAY_A );
|
||||
}
|
||||
}
|
||||
|
||||
// Export Field Names should be kept as they are and in case
|
||||
// they are changed later on, a fallback should be in place
|
||||
$valuesArray = array(
|
||||
'__comment' => $exportComment,
|
||||
'settings' => json_decode($settingsJson, ARRAY_A),
|
||||
|
||||
'homepage' => array(
|
||||
'unloads' => $frontPageNoLoadArray,
|
||||
'load_exceptions' => $frontPageExceptionsListArray
|
||||
),
|
||||
|
||||
'global_unload' => $globalUnloadArray,
|
||||
'bulk_unload' => $bulkUnloadArray,
|
||||
|
||||
'post_type_exceptions' => $postTypeLoadExceptionsArray,
|
||||
|
||||
// [wpacu_pro]
|
||||
'post_type_via_tax_exceptions' => $postTypeViaTaxLoadExceptionsArray,
|
||||
// [/wpacu_pro]
|
||||
|
||||
'global_data' => $globalDataListArray,
|
||||
|
||||
// [wpacu_pro]
|
||||
'extras_exceptions' => $extrasLoadExceptionsArray,
|
||||
// [/wpacu_pro]
|
||||
|
||||
'posts_metas' => $allMetaResults['postmeta'],
|
||||
);
|
||||
} else {
|
||||
return; // has to be "Settings" or "Everything"
|
||||
}
|
||||
|
||||
// Was the right selection made? Continue
|
||||
$date = date('j-M-Y-H.i');
|
||||
$host = parse_url(site_url(), PHP_URL_HOST);
|
||||
|
||||
$wpacuExportForPartOfFileName = str_replace('_', '-', $wpacuExportFor);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('Content-Disposition: attachment; filename="asset-cleanup-lite-exported-'.$wpacuExportForPartOfFileName.'-from-'.$host.'-'.$date.'.json"');
|
||||
|
||||
echo wp_json_encode($valuesArray);
|
||||
exit();
|
||||
}
|
||||
/***** END EXPORT ******/
|
||||
|
||||
/***** BEGIN IMPORT ******/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doImport()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! Misc::getVar('post', 'wpacu_do_import_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$jsonTmpName = isset($_FILES['wpacu_import_file']['tmp_name']) ? $_FILES['wpacu_import_file']['tmp_name'] : false;
|
||||
|
||||
if (! $jsonTmpName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Last important check
|
||||
\check_admin_referer('wpacu_do_import', 'wpacu_do_import_nonce');
|
||||
|
||||
if (! is_file($jsonTmpName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$valuesJson = FileSystem::fileGetContents($jsonTmpName);
|
||||
|
||||
$valuesArray = json_decode($valuesJson, ARRAY_A);
|
||||
|
||||
if ( ! (JSON_ERROR_NONE === Misc::jsonLastError())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$importedList = array();
|
||||
|
||||
// NOTE: The values are not replaced, but added to the existing ones (if any)
|
||||
|
||||
// "Settings" (Replace)
|
||||
if (isset($valuesArray['settings']) && ! empty($valuesArray['settings'])) {
|
||||
$wpacuSettings = new Settings();
|
||||
|
||||
// "Site-wide Common Unloads" - apply settings
|
||||
|
||||
// JS
|
||||
$disableJQueryMigrate = isset( $valuesArray['settings']['disable_jquery_migrate'] ) ? $valuesArray['settings']['disable_jquery_migrate'] : false;
|
||||
$disableCommentReply = isset( $valuesArray['settings']['disable_comment_reply'] ) ? $valuesArray['settings']['disable_comment_reply'] : false;
|
||||
|
||||
// CSS
|
||||
$disableGutenbergCssBlockLibrary = isset( $valuesArray['settings']['disable_wp_block_library'] ) ? $valuesArray['settings']['disable_wp_block_library'] : false;
|
||||
$disableDashiconsForGuests = isset( $valuesArray['settings']['disable_dashicons_for_guests'] ) ? $valuesArray['settings']['disable_dashicons_for_guests'] : false;
|
||||
|
||||
$wpacuSettings->updateSiteWideRuleForCommonAssets(
|
||||
array(
|
||||
// JS
|
||||
'jquery_migrate' => $disableJQueryMigrate,
|
||||
'comment_reply' => $disableCommentReply,
|
||||
|
||||
// CSS
|
||||
'wp_block_library' => $disableGutenbergCssBlockLibrary,
|
||||
'dashicons' => $disableDashiconsForGuests,
|
||||
)
|
||||
);
|
||||
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_settings', wp_json_encode($valuesArray['settings']));
|
||||
$importedList[] = 'settings';
|
||||
}
|
||||
|
||||
// "Homepage" Unloads
|
||||
if (isset($valuesArray['homepage']['unloads']['scripts'])
|
||||
|| isset($valuesArray['homepage']['unloads']['styles'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_front_page_no_load', wp_json_encode($valuesArray['homepage']['unloads']));
|
||||
$importedList[] = 'homepage_unloads';
|
||||
}
|
||||
|
||||
// "Homepage" Load Exceptions
|
||||
if (isset($valuesArray['homepage']['load_exceptions']['scripts'])
|
||||
|| isset($valuesArray['homepage']['load_exceptions']['styles'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_front_page_load_exceptions', wp_json_encode($valuesArray['homepage']['load_exceptions']));
|
||||
$importedList[] = 'homepage_exceptions';
|
||||
}
|
||||
|
||||
// "Site-Wide" (Everywhere) Unloads
|
||||
if (isset($valuesArray['global_unload']['scripts'])
|
||||
|| isset($valuesArray['global_unload']['styles'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_global_unload', wp_json_encode($valuesArray['global_unload']));
|
||||
$importedList[] = 'sitewide_unloads';
|
||||
}
|
||||
|
||||
// Bulk Unloads (e.g. Unload on all pages of product post type)
|
||||
if (isset($valuesArray['bulk_unload']['scripts'])
|
||||
|| isset($valuesArray['bulk_unload']['styles'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_bulk_unload', wp_json_encode($valuesArray['bulk_unload']));
|
||||
$importedList[] = 'bulk_unload';
|
||||
}
|
||||
|
||||
// Post type: load exception
|
||||
if (isset($valuesArray['post_type_exceptions']) && ! empty($valuesArray['post_type_exceptions'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_post_type_load_exceptions', wp_json_encode($valuesArray['post_type_exceptions']));
|
||||
$importedList[] = 'post_type_load_exceptions';
|
||||
}
|
||||
|
||||
// [wpacu_pro]
|
||||
// Post type: load exception via taxonomy
|
||||
if (isset($valuesArray['post_type_via_tax_exceptions']) && ! empty($valuesArray['post_type_via_tax_exceptions'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_post_type_via_tax_exceptions', wp_json_encode($valuesArray['post_type_via_tax_exceptions']));
|
||||
$importedList[] = 'post_type_via_tax_exceptions';
|
||||
}
|
||||
// [/wpacu_pro]
|
||||
|
||||
// Global Data
|
||||
if (isset($valuesArray['global_data']['scripts'])
|
||||
|| isset($valuesArray['global_data']['styles'])) {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_global_data', wp_json_encode($valuesArray['global_data']));
|
||||
$importedList[] = 'global_data';
|
||||
}
|
||||
|
||||
// [START] All Posts Metas (per page unloads, load exceptions, page options from side meta box)
|
||||
$targetKey = 'posts_metas';
|
||||
|
||||
if (isset($valuesArray[$targetKey]) && ! empty($valuesArray[$targetKey])) {
|
||||
foreach ($valuesArray[$targetKey] as $metaValues) {
|
||||
// It needs to have a post ID and meta key starting with _' . WPACU_PLUGIN_ID . '
|
||||
if ( ! (isset($metaValues['post_id'], $metaValues['meta_key'])
|
||||
&& strpos($metaValues['meta_key'], '_' . WPACU_PLUGIN_ID) === 0) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$postId = $metaValues['post_id'];
|
||||
$metaKey = $metaValues['meta_key'];
|
||||
$metaValue = $metaValues['meta_value']; // already JSON encoded
|
||||
|
||||
if (! add_post_meta($postId, $metaKey, $metaValue, true)) {
|
||||
update_post_meta($postId, $metaKey, $metaValue);
|
||||
}
|
||||
}
|
||||
|
||||
$importedList[] = 'posts_metas';
|
||||
}
|
||||
// [END] All Posts Metas (per page unloads, load exceptions, page options from side meta box)
|
||||
|
||||
if (! empty($importedList)) {
|
||||
// After import was completed, clear all CSS/JS cache
|
||||
OptimizeCommon::clearCache();
|
||||
|
||||
set_transient('wpacu_import_done', $importedList, 30);
|
||||
|
||||
wp_redirect(admin_url('admin.php?page=wpassetcleanup_tools&wpacu_for=import_export&wpacu_import_done=1&wpacu_time=' . time()));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
/***** END IMPORT ******/
|
||||
}
|
136
wp-content/plugins/wp-asset-clean-up/classes/Info.php
Normal file
136
wp-content/plugins/wp-asset-clean-up/classes/Info.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Gets information pages such as "Getting Started", "Help" and "Info"
|
||||
* Retrieves specific information about a plugin or a theme
|
||||
*
|
||||
* Class Info
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Info
|
||||
{
|
||||
/**
|
||||
* Info constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action('wpacu_assets_plugin_notice_table_row', array($this, 'pluginNotice'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function gettingStarted()
|
||||
{
|
||||
$data = array('for' => 'how-it-works');
|
||||
|
||||
if (isset($_GET['wpacu_for'])) {
|
||||
$data['for'] = sanitize_text_field($_GET['wpacu_for']);
|
||||
}
|
||||
|
||||
Main::instance()->parseTemplate('admin-page-getting-started', $data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function help()
|
||||
{
|
||||
Main::instance()->parseTemplate('admin-page-get-help', array(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function pagesInfo()
|
||||
{
|
||||
Main::instance()->parseTemplate('admin-page-pages-info', array(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function license()
|
||||
{
|
||||
Main::instance()->parseTemplate('admin-page-license', array(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locationChild
|
||||
* @param $allPlugins
|
||||
* @param $allActivePluginsIcons
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getPluginInfo($locationChild, $allPlugins, $allActivePluginsIcons)
|
||||
{
|
||||
foreach (array_keys($allPlugins) as $pluginFile) {
|
||||
if (strpos($pluginFile, $locationChild.'/') === 0) {
|
||||
$imageIconStyle = $classIconStyle = '';
|
||||
|
||||
if (isset($allActivePluginsIcons[$locationChild]) && $allActivePluginsIcons[$locationChild]) {
|
||||
$classIconStyle = 'has-icon';
|
||||
$imageIconStyle = 'style="background: transparent url(\''.$allActivePluginsIcons[$locationChild].'\') no-repeat 0 0; background-size: cover;"';
|
||||
}
|
||||
|
||||
return '<div class="icon-plugin-default '.$classIconStyle.'"><div class="icon-area" '.$imageIconStyle.'></div></div> <span class="wpacu-child-location-name">'.$allPlugins[$pluginFile]['Name'].'</span>' . ' <span class="wpacu-child-location-version">v'.$allPlugins[$pluginFile]['Version'].'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return $locationChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locationChild
|
||||
* @param $allThemes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getThemeInfo($locationChild, $allThemes)
|
||||
{
|
||||
foreach (array_keys($allThemes) as $themeDir) {
|
||||
if ($locationChild === $themeDir) {
|
||||
$themeInfo = wp_get_theme($themeDir);
|
||||
$themeIconUrl = Misc::getThemeIcon($themeInfo->get('Name'));
|
||||
|
||||
$themeIconHtml = '';
|
||||
$hasIcon = false;
|
||||
|
||||
if ($themeIconUrl) {
|
||||
$hasIcon = true;
|
||||
$imageIconStyle = 'style="background: transparent url(\''.$themeIconUrl.'\') no-repeat 0 0; background-size: cover;"';
|
||||
$themeIconHtml = '<div class="icon-theme has-icon"><div class="icon-area" '.$imageIconStyle.'></div></div>';
|
||||
}
|
||||
|
||||
$output = $themeIconHtml . $themeInfo->get('Name') . ' <span class="wpacu-child-location-version">v'.$themeInfo->get('Version').'</span>';
|
||||
|
||||
return array('has_icon' => $hasIcon, 'output' => $output);
|
||||
}
|
||||
}
|
||||
|
||||
return array('has_icon' => false, 'output' => $locationChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notices about consequences in unloading assets from specific plugins
|
||||
*
|
||||
* @param $plugin
|
||||
*/
|
||||
public function pluginNotice($plugin)
|
||||
{
|
||||
// Elementor, Elementor Pro
|
||||
if (in_array($plugin, array('elementor', 'elementor-pro'))) {
|
||||
$wpacuPluginTitle = WPACU_PLUGIN_TITLE;
|
||||
?>
|
||||
<tr class="wpacu_asset_row wpacu_notice_row">
|
||||
<td valign="top">
|
||||
<div class="wpacu-warning">
|
||||
<p style="margin: 0 0 4px !important;"><small><span class="dashicons dashicons-warning"></span> Most (if not all) of this plugin's files are linked (child & parent) for maximum compatibility. Unloading one Elementor CSS/JS will likely trigger the unloading of other "children" associated with it. <strong>To avoid breaking the Elementor editor, <?php echo esc_html($wpacuPluginTitle); ?> is deactivated in the page builder's edit & preview mode. If this page is not edited via Elementor and you don't need any of the plugin's functionality (widgets, templates etc.) here, you can unload the files below making sure to test the page after you updated it.</strong></small></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
50
wp-content/plugins/wp-asset-clean-up/classes/Lite.php
Normal file
50
wp-content/plugins/wp-asset-clean-up/classes/Lite.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* The code is triggered only in Asset CleanUp Lite
|
||||
*
|
||||
* Class Lite
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Lite
|
||||
{
|
||||
/**
|
||||
* Lite constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action('current_screen', array($this, 'currentScreen'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function currentScreen()
|
||||
{
|
||||
$current_screen = \get_current_screen();
|
||||
|
||||
if ($current_screen->base === 'term' && isset($current_screen->taxonomy) && $current_screen->taxonomy != '') {
|
||||
add_action ($current_screen->taxonomy . '_edit_form_fields', static function ($tag) {
|
||||
?>
|
||||
<tr class="form-field">
|
||||
<th scope="row" valign="top"><label for="wpassetcleanup_list"><?php echo WPACU_PLUGIN_TITLE; ?>: <?php _e('CSS & JavaScript Load Manager', 'wp-asset-clean-up'); ?></label></th>
|
||||
<td data-wpacu-taxonomy="<?php echo esc_attr($tag->taxonomy); ?>">
|
||||
<img width="20" height="20" src="<?php echo esc_url(WPACU_PLUGIN_URL); ?>/assets/icons/icon-lock.svg" valign="top" alt="" />
|
||||
<?php
|
||||
echo sprintf(
|
||||
__('Managing the loading of the styles & scripts files for this <strong>%s</strong> taxonomy is %savailable in the Pro version%s', 'wp-asset-clean-up'),
|
||||
$tag->taxonomy,
|
||||
'<a href="'.apply_filters('wpacu_go_pro_affiliate_link', WPACU_PLUGIN_GO_PRO_URL.'?utm_source=taxonomy_edit_page&utm_medium=upgrade_link').'" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
3543
wp-content/plugins/wp-asset-clean-up/classes/Main.php
Normal file
3543
wp-content/plugins/wp-asset-clean-up/classes/Main.php
Normal file
File diff suppressed because it is too large
Load Diff
696
wp-content/plugins/wp-asset-clean-up/classes/Maintenance.php
Normal file
696
wp-content/plugins/wp-asset-clean-up/classes/Maintenance.php
Normal file
@ -0,0 +1,696 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
|
||||
/**
|
||||
* Class Maintenance
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Maintenance
|
||||
{
|
||||
/**
|
||||
* Maintenance constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Schedule cron events
|
||||
add_action('wp', array($this, 'scheduleEvents'));
|
||||
add_action('init', array($this, 'scheduleTrigger'));
|
||||
|
||||
if (is_admin() && Menu::isPluginPage()) {
|
||||
add_action('admin_init', static function() {
|
||||
Maintenance::cleanUnusedAssetsFromInfoArea();
|
||||
Maintenance::combineNewOptionUpdate(); // Since v1.1.7.3 (Pro) & v1.3.6.4 (Lite)
|
||||
|
||||
OptimizeCommon::limitAlreadyMarkedAsMinified(); // Since v1.1.7.4 (Pro) & v1.3.6.6 (Lite)
|
||||
});
|
||||
}
|
||||
|
||||
add_action('init', static function() {
|
||||
if ( is_user_logged_in() && Menu::userCanManageAssets() ) {
|
||||
Maintenance::combineNewOptionUpdate(); // Since v1.1.7.3 (Pro) & v1.3.6.4 (Lite)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule events
|
||||
*
|
||||
* @access private
|
||||
* @since 1.6
|
||||
* @return void
|
||||
*/
|
||||
public function scheduleEvents()
|
||||
{
|
||||
// Daily events
|
||||
if (! wp_next_scheduled('wpacu_daily_scheduled_events')) {
|
||||
wp_schedule_event(current_time('timestamp', true), 'daily', 'wpacu_daily_scheduled_events');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger scheduled events
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function scheduleTrigger()
|
||||
{
|
||||
// Debugging purposes: trigger directly the code meant to be scheduled
|
||||
if (current_user_can('administrator')) {
|
||||
if (isset($_GET['wpacu_toggle_inline_code_to_combined_assets'])) {
|
||||
self::updateAppendOrNotInlineCodeToCombinedAssets(true);
|
||||
}
|
||||
|
||||
if (isset($_GET['wpacu_clear_cache_conditionally'])) {
|
||||
self::updateAppendOrNotInlineCodeToCombinedAssets(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (Misc::doingCron()) {
|
||||
add_action('wpacu_daily_scheduled_events', array($this, 'triggerDailyScheduleEvents'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function triggerDailyScheduleEvents()
|
||||
{
|
||||
self::updateAppendOrNotInlineCodeToCombinedAssets();
|
||||
self::clearCacheConditionally();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param false $isDebug
|
||||
*/
|
||||
public static function updateAppendOrNotInlineCodeToCombinedAssets($isDebug = false)
|
||||
{
|
||||
// WordPress Version below 5.5? Skip appending CSS/JS code to the combine CSS/JS list
|
||||
if ( ! Misc::isWpVersionAtLeast('5.5') ) {
|
||||
$settingsClass = new Settings();
|
||||
$optionsToUpdate = array(
|
||||
'_combine_loaded_css_append_handle_extra' => '',
|
||||
'_combine_loaded_js_append_handle_extra' => ''
|
||||
);
|
||||
$settingsClass->updateOption(array_keys($optionsToUpdate), array_values($optionsToUpdate));
|
||||
|
||||
if ($isDebug) {
|
||||
echo 'The WordPress version is below 5.5, thus there is no appending of the inline CSS/JS code to the combine CSS/JS list';
|
||||
}
|
||||
} else {
|
||||
// Check if there are too many .css /.js combined files in the caching directory and change settings
|
||||
// to prevent the appending of the inline CSS/JS code that is likely the culprit of so many files
|
||||
$settingsClass = new Settings();
|
||||
$settings = $settingsClass->getAll( true );
|
||||
$settingsClass::toggleAppendInlineAssocCodeHiddenSettings( $settings, true, $isDebug );
|
||||
}
|
||||
|
||||
if ($isDebug) {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param false $isDebug
|
||||
*/
|
||||
public static function clearCacheConditionally($isDebug = false)
|
||||
{
|
||||
// Clear caching if it wasn't cleared in the past 24 hours (e.g. the admin hasn't used the plugin for a while)
|
||||
$wpacuLastClearCache = get_transient('wpacu_last_clear_cache');
|
||||
|
||||
if ($isDebug) {
|
||||
echo 'Cache cleared last time: '.$wpacuLastClearCache.'<br />';
|
||||
}
|
||||
|
||||
if ($wpacuLastClearCache && (strtotime( '-1 days' ) > $wpacuLastClearCache)) {
|
||||
OptimizeCommon::clearCache();
|
||||
|
||||
if ($isDebug) {
|
||||
echo 'The cache was just cleared as it was not cleared in the past 24 hours.<br />';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function cleanUnusedAssetsFromInfoArea()
|
||||
{
|
||||
$allAssetsWithAtLeastOneRule = Overview::handlesWithAtLeastOneRule();
|
||||
|
||||
if (empty($allAssetsWithAtLeastOneRule)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stored in the "assets_info" key from "wpassetcleanup_global_data" option name (from `{$wpdb->prefix}options` table)
|
||||
$allAssetsFromInfoArea = Main::getHandlesInfo();
|
||||
|
||||
$handlesToClearFromInfo = array('styles' => array(), 'scripts' => array());
|
||||
|
||||
foreach (array('styles', 'scripts') as $assetType) {
|
||||
if ( isset( $allAssetsFromInfoArea[$assetType] ) && ! empty( $allAssetsFromInfoArea[$assetType] ) ) {
|
||||
foreach ( array_keys( $allAssetsFromInfoArea[$assetType] ) as $assetHandle ) {
|
||||
if ( ! isset($allAssetsWithAtLeastOneRule[$assetType][$assetHandle]) ) { // not found in $allAssetsWithAtLeastOneRule? Add it to the clear list
|
||||
$handlesToClearFromInfo[$assetType][] = $assetHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($handlesToClearFromInfo['styles']) || ! empty($handlesToClearFromInfo['scripts'])) {
|
||||
self::removeHandlesInfoFromGlobalDataOption($handlesToClearFromInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function combineNewOptionUpdate()
|
||||
{
|
||||
$settingsClass = new Settings();
|
||||
$pluginSettings = $settingsClass->getAll();
|
||||
|
||||
if ( ($pluginSettings['combine_loaded_css'] === 'for_admin' ||
|
||||
(isset($pluginSettings['combine_loaded_css_for_admin_only']) && $pluginSettings['combine_loaded_css_for_admin_only'] == 1) )
|
||||
&& Menu::userCanManageAssets() ) {
|
||||
$settingsClass->updateOption('combine_loaded_css', '');
|
||||
$settingsClass->updateOption('combine_loaded_css_for_admin_only', '');
|
||||
}
|
||||
|
||||
if ( ($pluginSettings['combine_loaded_js'] === 'for_admin' ||
|
||||
(isset($pluginSettings['combine_loaded_js_for_admin_only']) && $pluginSettings['combine_loaded_js_for_admin_only'] == 1) )
|
||||
&& Menu::userCanManageAssets() ) {
|
||||
$settingsClass->updateOption('combine_loaded_js', '');
|
||||
$settingsClass->updateOption('combine_loaded_js_for_admin_only', '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $handlesToClearFromInfo
|
||||
*/
|
||||
public static function removeHandlesInfoFromGlobalDataOption($handlesToClearFromInfo)
|
||||
{
|
||||
$optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
|
||||
$globalKey = 'assets_info';
|
||||
|
||||
$existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
|
||||
$existingListJson = get_option($optionToUpdate);
|
||||
|
||||
$existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
|
||||
$existingList = $existingListData['list'];
|
||||
|
||||
// $assetType could be 'styles' or 'scripts'
|
||||
foreach ($handlesToClearFromInfo as $assetType => $handles) {
|
||||
foreach ($handles as $handle) {
|
||||
if ( isset( $existingList[ $assetType ][ $globalKey ][ $handle ] ) ) {
|
||||
unset( $existingList[ $assetType ][ $globalKey ][ $handle ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
|
||||
}
|
||||
|
||||
/**
|
||||
* When is this needed? Sometimes, you have rules such as "Unload site-wide (everywhere)" and load exceptions associated to it
|
||||
* However, if you remove the unload rule, then the load exceptions associated with it will become useless as they worth together
|
||||
* If no unload rule is added, the file is loaded anyway, it doesn't need any load exception obviously
|
||||
*
|
||||
* @param $assetHandle
|
||||
* @param $assetType | it belongs to "styles" or "scripts"
|
||||
*/
|
||||
public static function removeAllLoadExceptionsFor($assetHandle, $assetType)
|
||||
{
|
||||
/*
|
||||
* Any in the front-page?
|
||||
*/
|
||||
$wpacuFrontPageLoadExceptions = get_option(WPACU_PLUGIN_ID . '_front_page_load_exceptions');
|
||||
|
||||
if ($wpacuFrontPageLoadExceptions) {
|
||||
$wpacuFrontPageLoadExceptionsArray = @json_decode( $wpacuFrontPageLoadExceptions, ARRAY_A );
|
||||
|
||||
$targetArray = isset($wpacuFrontPageLoadExceptionsArray[$assetType]) && is_array($wpacuFrontPageLoadExceptionsArray[$assetType])
|
||||
? $wpacuFrontPageLoadExceptionsArray[$assetType]
|
||||
: array();
|
||||
|
||||
if ( in_array($assetHandle, $targetArray) ) {
|
||||
$targetKey = array_search($assetHandle, $targetArray);
|
||||
unset($wpacuFrontPageLoadExceptionsArray[$assetType][$targetKey]); // clear the exception
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_front_page_load_exceptions',
|
||||
wp_json_encode(Misc::filterList($wpacuFrontPageLoadExceptionsArray))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Any for all pages of a certain post type? (e.g. in all WooCommerce "product" pages)
|
||||
*/
|
||||
$wpacuPostTypeLoadExceptions = get_option(WPACU_PLUGIN_ID . '_post_type_load_exceptions');
|
||||
|
||||
if ($wpacuPostTypeLoadExceptions) {
|
||||
$wpacuPostTypeLoadExceptionsArray = @json_decode( $wpacuPostTypeLoadExceptions, ARRAY_A );
|
||||
|
||||
if (! empty($wpacuPostTypeLoadExceptionsArray)) {
|
||||
foreach ($wpacuPostTypeLoadExceptionsArray as $dbPostType => $dbList) {
|
||||
foreach ($dbList as $dbAssetType => $dbValues) {
|
||||
if ($assetType === $dbAssetType && array_key_exists( $assetHandle, $dbValues ) ) {
|
||||
unset($wpacuPostTypeLoadExceptionsArray[$dbPostType][$dbAssetType][$assetHandle]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_post_type_load_exceptions',
|
||||
wp_json_encode(Misc::filterList($wpacuPostTypeLoadExceptionsArray))
|
||||
);
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$wpacuPluginId = WPACU_PLUGIN_ID;
|
||||
|
||||
/*
|
||||
* Any for posts (any kind), pages, taxonomies or users?
|
||||
*/
|
||||
foreach (array($wpdb->postmeta, $wpdb->termmeta, $wpdb->usermeta) as $tableName) {
|
||||
$wpacuGetValuesQuery = <<<SQL
|
||||
SELECT * FROM `{$tableName}` WHERE meta_key='_{$wpacuPluginId}_load_exceptions'
|
||||
SQL;
|
||||
$wpacuMetaData = $wpdb->get_results( $wpacuGetValuesQuery, ARRAY_A );
|
||||
|
||||
foreach ( $wpacuMetaData as $wpacuValues ) {
|
||||
$decodedValues = @json_decode( $wpacuValues['meta_value'], ARRAY_A );
|
||||
|
||||
if ( empty( $decodedValues ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( isset( $decodedValues[ $assetType ] ) &&
|
||||
is_array( $decodedValues[ $assetType ] ) &&
|
||||
in_array( $assetHandle, $decodedValues[ $assetType ] ) ) {
|
||||
$targetKey = array_search( $assetHandle, $decodedValues[ $assetType ] );
|
||||
unset( $decodedValues[ $assetType ][ $targetKey ] ); // clear the exception
|
||||
} else {
|
||||
continue; // no point in re-updating the database with the same values
|
||||
}
|
||||
|
||||
$newList = wp_json_encode(Misc::filterList($decodedValues));
|
||||
|
||||
if ( $tableName === $wpdb->postmeta ) {
|
||||
update_post_meta($wpacuValues['post_id'], '_'.$wpacuPluginId.'_load_exceptions', $newList);
|
||||
} elseif ( $tableName === $wpdb->termmeta ) {
|
||||
update_term_meta($wpacuValues['term_id'], '_'.$wpacuPluginId.'_load_exceptions', $newList);
|
||||
} else {
|
||||
update_user_meta($wpacuValues['user_id'], '_'.$wpacuPluginId.'_load_exceptions', $newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Any load exceptions for 404, search, date pages?
|
||||
*/
|
||||
$wpacuExtrasLoadExceptions = get_option(WPACU_PLUGIN_ID . '_extras_load_exceptions');
|
||||
|
||||
if ($wpacuExtrasLoadExceptions) {
|
||||
$wpacuExtrasLoadExceptionsArray = @json_decode( $wpacuExtrasLoadExceptions, ARRAY_A );
|
||||
|
||||
// $forKey could be '404', 'search', 'date', etc.
|
||||
foreach ($wpacuExtrasLoadExceptionsArray as $forKey => $values) {
|
||||
$targetArray = isset( $values[ $assetType ] ) && is_array( $values[ $assetType ] ) ? $values[ $assetType ] : array();
|
||||
|
||||
if ( in_array( $assetHandle, $targetArray ) ) {
|
||||
$targetKey = array_search( $assetHandle, $targetArray );
|
||||
unset( $wpacuExtrasLoadExceptionsArray[ $forKey ][ $assetType ][ $targetKey ] ); // clear the exception
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_extras_load_exceptions',
|
||||
wp_json_encode( Misc::filterList( $wpacuExtrasLoadExceptionsArray ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Any (RegEx / Logged-in User) load exceptions?
|
||||
*/
|
||||
$dbListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
$globalKeys = array('load_regex', 'load_it_logged_in');
|
||||
|
||||
foreach ($globalKeys as $globalKey) {
|
||||
if ( $dbListJson ) {
|
||||
$dbList = @json_decode( $dbListJson, ARRAY_A );
|
||||
|
||||
$targetArray = isset( $dbList[ $assetType ][ $globalKey ] ) &&
|
||||
is_array( $dbList[ $assetType ][ $globalKey ] )
|
||||
? $dbList[ $assetType ][ $globalKey ] : array();
|
||||
|
||||
if ( array_key_exists( $assetHandle, $targetArray ) ) {
|
||||
unset( $dbList[ $assetType ][ $globalKey ][ $assetHandle ] ); // clear the exception
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_global_data',
|
||||
wp_json_encode( Misc::filterList( $dbList ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $assetHandle
|
||||
* @param $assetType
|
||||
*/
|
||||
public static function removeAllRulesFor($assetHandle, $assetType)
|
||||
{
|
||||
// Clear any load exception rules
|
||||
self::removeAllLoadExceptionsFor($assetHandle, $assetType);
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_global_data'
|
||||
* Global (Site-wide) Rules: Preloading, Position changing, Unload via RegEx, etc.
|
||||
*/
|
||||
$wpacuGlobalData = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
$wpacuGlobalDataArray = @json_decode($wpacuGlobalData, ARRAY_A);
|
||||
|
||||
foreach ( array(
|
||||
'404',
|
||||
'assets_info',
|
||||
'date',
|
||||
'everywhere',
|
||||
'ignore_child',
|
||||
'load_it_logged_in',
|
||||
'load_regex',
|
||||
'notes',
|
||||
'positions',
|
||||
'preloads',
|
||||
'search',
|
||||
'unload_regex' ) as $dataType ) {
|
||||
if ( isset( $wpacuGlobalDataArray[ $assetType ][ $dataType ] ) && ! empty( $wpacuGlobalDataArray[ $assetType ][ $dataType ] ) && array_key_exists($assetHandle, $wpacuGlobalDataArray[ $assetType ][ $dataType ]) ) {
|
||||
unset( $wpacuGlobalDataArray[ $assetType ][ $dataType ][ $assetHandle ]);
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_global_data',
|
||||
wp_json_encode( Misc::filterList( $wpacuGlobalDataArray ) )
|
||||
);
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_global_unload'
|
||||
* Unload Site-Wide (Everywhere)
|
||||
*/
|
||||
$wpacuGlobalUnloadData = get_option(WPACU_PLUGIN_ID . '_global_unload');
|
||||
$wpacuGlobalUnloadDataArray = @json_decode($wpacuGlobalUnloadData, ARRAY_A);
|
||||
|
||||
if (isset($wpacuGlobalUnloadDataArray[$assetType]) && ! empty($wpacuGlobalUnloadDataArray[$assetType]) && in_array($assetHandle, $wpacuGlobalUnloadDataArray[$assetType])) {
|
||||
$targetKey = array_search($assetHandle, $wpacuGlobalUnloadDataArray[$assetType]);
|
||||
unset($wpacuGlobalUnloadDataArray[$assetType][$targetKey]);
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_global_unload',
|
||||
wp_json_encode( Misc::filterList( $wpacuGlobalUnloadDataArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_bulk_unload'
|
||||
* Bulk Unload
|
||||
*/
|
||||
$wpacuBulkUnloadData = get_option(WPACU_PLUGIN_ID . '_bulk_unload');
|
||||
$wpacuBulkUnloadDataArray = @json_decode($wpacuBulkUnloadData, ARRAY_A);
|
||||
|
||||
if (isset($wpacuBulkUnloadDataArray[$assetType]) && ! empty($wpacuBulkUnloadDataArray[$assetType])) {
|
||||
foreach ($wpacuBulkUnloadDataArray[$assetType] as $unloadBulkType => $unloadBulkValues) {
|
||||
// $unloadBulkType could be 'post_type', 'date', '404', 'taxonomy', 'search', 'custom_post_type_archive_[custom_post_type]'
|
||||
if ($unloadBulkType === 'post_type') {
|
||||
foreach ($unloadBulkValues as $postType => $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$postType][$targetKey]);
|
||||
}
|
||||
}
|
||||
} elseif (in_array($unloadBulkType, array('date', '404', 'search')) || (strpos($unloadBulkType, 'custom_post_type_archive_') !== false)) {
|
||||
if (in_array($assetHandle, $unloadBulkValues)) {
|
||||
$targetKey = array_search($assetHandle, $unloadBulkValues);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$targetKey]);
|
||||
}
|
||||
} elseif ($unloadBulkType === 'taxonomy') {
|
||||
foreach ($unloadBulkValues as $taxonomyType => $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$taxonomyType][$targetKey]);
|
||||
}
|
||||
}
|
||||
} elseif ($unloadBulkType === 'author' && isset($unloadBulkValues['all']) && ! empty($unloadBulkValues['all'])) {
|
||||
foreach ($unloadBulkValues['all'] as $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType]['all'][$targetKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_bulk_unload',
|
||||
wp_json_encode( Misc::filterList( $wpacuBulkUnloadDataArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_front_page_no_load'
|
||||
* Homepage (Unloads)
|
||||
*/
|
||||
$wpacuFrontPageUnloads = get_option(WPACU_PLUGIN_ID . '_front_page_no_load');
|
||||
|
||||
if ($wpacuFrontPageUnloads) {
|
||||
$wpacuFrontPageUnloadsArray = @json_decode( $wpacuFrontPageUnloads, ARRAY_A );
|
||||
|
||||
if ( isset( $wpacuFrontPageUnloadsArray[$assetType] ) && ! empty( $wpacuFrontPageUnloadsArray[$assetType] ) && in_array( $assetHandle, $wpacuFrontPageUnloadsArray[$assetType] ) ) {
|
||||
$targetKey = array_search($assetHandle, $wpacuFrontPageUnloadsArray[$assetType]);
|
||||
unset($wpacuFrontPageUnloadsArray[$assetType][$targetKey]);
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_front_page_no_load',
|
||||
wp_json_encode( Misc::filterList( $wpacuFrontPageUnloadsArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_front_page_data'
|
||||
* Homepage (async, defer)
|
||||
*/
|
||||
$wpacuFrontPageData = ($assetType === 'scripts') && get_option(WPACU_PLUGIN_ID . '_front_page_data');
|
||||
|
||||
if ($wpacuFrontPageData) {
|
||||
$wpacuFrontPageDataArray = @json_decode( $wpacuFrontPageData, ARRAY_A );
|
||||
|
||||
if ( isset( $wpacuFrontPageDataArray[$assetType][$assetHandle] ) ) {
|
||||
unset( $wpacuFrontPageDataArray[$assetType][$assetHandle] );
|
||||
}
|
||||
|
||||
if ( isset( $wpacuFrontPageDataArray['scripts_attributes_no_load'][$assetHandle] ) ) {
|
||||
unset( $wpacuFrontPageDataArray['scripts_attributes_no_load'][$assetHandle] );
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_front_page_data',
|
||||
wp_json_encode( Misc::filterList( $wpacuFrontPageDataArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tables: $wpdb->postmeta, $wpdb->termmeta, $wpdb->usermeta (all part of the standard WordPress tables)
|
||||
* Plugin meta keys: _{$wpacuPluginId}_no_load', _{$wpacuPluginId}_data
|
||||
* Get all Asset CleanUp (Pro) meta keys from all WordPress meta tables where it can be possibly used
|
||||
*
|
||||
*/
|
||||
global $wpdb;
|
||||
$wpacuPluginId = WPACU_PLUGIN_ID;
|
||||
|
||||
foreach (array($wpdb->postmeta, $wpdb->termmeta, $wpdb->usermeta) as $tableName) {
|
||||
$wpacuGetValuesQuery = <<<SQL
|
||||
SELECT * FROM `{$tableName}`
|
||||
WHERE meta_key IN('_{$wpacuPluginId}_no_load', '_{$wpacuPluginId}_data')
|
||||
SQL;
|
||||
$wpacuMetaData = $wpdb->get_results( $wpacuGetValuesQuery, ARRAY_A );
|
||||
|
||||
foreach ( $wpacuMetaData as $wpacuValues ) {
|
||||
$decodedValues = @json_decode( $wpacuValues['meta_value'], ARRAY_A );
|
||||
|
||||
// No load rules
|
||||
if ( $wpacuValues['meta_key'] === '_' . $wpacuPluginId . '_no_load' && isset( $decodedValues[$assetType] ) && in_array($assetHandle, $decodedValues[$assetType]) ) {
|
||||
$targetKey = array_search($assetHandle, $decodedValues[$assetType]);
|
||||
unset($decodedValues[$assetType][$targetKey]);
|
||||
|
||||
if ($tableName === $wpdb->postmeta) {
|
||||
update_post_meta($wpacuValues['post_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->termmeta) {
|
||||
update_term_meta($wpacuValues['term_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->usermeta) {
|
||||
update_user_meta($wpacuValues['user_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Other rules such as script attribute (e.g. async, defer)
|
||||
if ( $wpacuValues['meta_key'] === '_' . $wpacuPluginId . '_data' ) {
|
||||
if ( isset( $decodedValues[$assetType][$assetHandle] ) ) {
|
||||
unset( $decodedValues[ $assetType ][ $assetHandle ] );
|
||||
}
|
||||
|
||||
// Load exceptions for script attributes
|
||||
if ( $assetType === 'scripts' && isset( $decodedValues['scripts_attributes_no_load'][$assetHandle] ) ) {
|
||||
unset($decodedValues['scripts_attributes_no_load'][$assetHandle]);
|
||||
}
|
||||
|
||||
if ($tableName === $wpdb->postmeta) {
|
||||
update_post_meta($wpacuValues['post_id'], '_' . $wpacuPluginId . '_data', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->termmeta) {
|
||||
update_term_meta($wpacuValues['term_id'], '_' . $wpacuPluginId . '_data', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->usermeta) {
|
||||
update_user_meta($wpacuValues['user_id'], '_' . $wpacuPluginId . '_data', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all unload rules apart from the site-wide one
|
||||
*
|
||||
* @param $assetHandle
|
||||
* @param $assetType
|
||||
*/
|
||||
public static function removeAllRedundantUnloadRulesFor($assetHandle, $assetType)
|
||||
{
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_front_page_no_load'
|
||||
* Homepage (Unloads)
|
||||
*/
|
||||
$wpacuFrontPageUnloads = get_option(WPACU_PLUGIN_ID . '_front_page_no_load');
|
||||
|
||||
if ($wpacuFrontPageUnloads) {
|
||||
$wpacuFrontPageUnloadsArray = @json_decode( $wpacuFrontPageUnloads, ARRAY_A );
|
||||
|
||||
if ( isset( $wpacuFrontPageUnloadsArray[$assetType] ) && ! empty( $wpacuFrontPageUnloadsArray[$assetType] ) && in_array( $assetHandle, $wpacuFrontPageUnloadsArray[$assetType] ) ) {
|
||||
$targetKey = array_search($assetHandle, $wpacuFrontPageUnloadsArray[$assetType]);
|
||||
unset($wpacuFrontPageUnloadsArray[$assetType][$targetKey]);
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_front_page_no_load',
|
||||
wp_json_encode( Misc::filterList( $wpacuFrontPageUnloadsArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_bulk_unload'
|
||||
* Bulk Unload
|
||||
*/
|
||||
$wpacuBulkUnloadData = get_option(WPACU_PLUGIN_ID . '_bulk_unload');
|
||||
$wpacuBulkUnloadDataArray = @json_decode($wpacuBulkUnloadData, ARRAY_A);
|
||||
|
||||
if (isset($wpacuBulkUnloadDataArray[$assetType]) && ! empty($wpacuBulkUnloadDataArray[$assetType])) {
|
||||
foreach ($wpacuBulkUnloadDataArray[$assetType] as $unloadBulkType => $unloadBulkValues) {
|
||||
// $unloadBulkType could be 'post_type', 'date', '404', 'taxonomy', 'search', 'custom_post_type_archive_[custom_post_type]'
|
||||
if ($unloadBulkType === 'post_type') {
|
||||
foreach ($unloadBulkValues as $postType => $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$postType][$targetKey]);
|
||||
}
|
||||
}
|
||||
// [Any Pro left overs]
|
||||
} elseif ($unloadBulkType === 'post_type_via_tax') {
|
||||
foreach ($unloadBulkValues as $postType => $assetHandlesValues) {
|
||||
if (isset($assetHandlesValues[$assetHandle]) && is_array($assetHandlesValues[$assetHandle])) {
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$postType][$assetHandle]);
|
||||
}
|
||||
}
|
||||
} elseif (in_array($unloadBulkType, array('date', '404', 'search')) || (strpos($unloadBulkType, 'custom_post_type_archive_') !== false)) {
|
||||
if (in_array($assetHandle, $unloadBulkValues)) {
|
||||
$targetKey = array_search($assetHandle, $unloadBulkValues);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$targetKey]);
|
||||
}
|
||||
} elseif ($unloadBulkType === 'taxonomy') {
|
||||
foreach ($unloadBulkValues as $taxonomyType => $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType][$taxonomyType][$targetKey]);
|
||||
}
|
||||
}
|
||||
} elseif ($unloadBulkType === 'author' && isset($unloadBulkValues['all']) && ! empty($unloadBulkValues['all'])) {
|
||||
foreach ($unloadBulkValues['all'] as $assetHandles) {
|
||||
if (in_array($assetHandle, $assetHandles)) {
|
||||
$targetKey = array_search($assetHandle, $assetHandles);
|
||||
unset($wpacuBulkUnloadDataArray[$assetType][$unloadBulkType]['all'][$targetKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// [/Any Pro left overs]
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_bulk_unload',
|
||||
wp_json_encode( Misc::filterList( $wpacuBulkUnloadDataArray ) )
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tables: $wpdb->postmeta, $wpdb->termmeta, $wpdb->usermeta (all part of the standard WordPress tables)
|
||||
* Plugin meta key: _{$wpacuPluginId}_no_load'
|
||||
*
|
||||
*/
|
||||
global $wpdb;
|
||||
$wpacuPluginId = WPACU_PLUGIN_ID;
|
||||
|
||||
foreach (array($wpdb->postmeta, $wpdb->termmeta, $wpdb->usermeta) as $tableName) {
|
||||
$wpacuGetValuesQuery = <<<SQL
|
||||
SELECT * FROM `{$tableName}` WHERE meta_key='_{$wpacuPluginId}_no_load'
|
||||
SQL;
|
||||
$wpacuMetaData = $wpdb->get_results( $wpacuGetValuesQuery, ARRAY_A );
|
||||
|
||||
foreach ( $wpacuMetaData as $wpacuValues ) {
|
||||
$decodedValues = @json_decode( $wpacuValues['meta_value'], ARRAY_A );
|
||||
|
||||
// No load rules
|
||||
if ( isset( $decodedValues[$assetType] ) && in_array($assetHandle, $decodedValues[$assetType]) ) {
|
||||
$targetKey = array_search($assetHandle, $decodedValues[$assetType]);
|
||||
unset($decodedValues[$assetType][$targetKey]);
|
||||
|
||||
if ($tableName === $wpdb->postmeta) {
|
||||
update_post_meta($wpacuValues['post_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->termmeta) {
|
||||
update_term_meta($wpacuValues['term_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
} elseif ($tableName === $wpdb->usermeta) {
|
||||
update_user_meta($wpacuValues['user_id'], '_' . $wpacuPluginId . '_no_load', wp_json_encode( Misc::filterList( $decodedValues ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Table: WPACU_PLUGIN_ID . '_global_data'
|
||||
* Global (Site-wide) Rules: Unload via RegEx
|
||||
*/
|
||||
$wpacuGlobalData = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
$wpacuGlobalDataArray = @json_decode($wpacuGlobalData, ARRAY_A);
|
||||
|
||||
foreach ( array( 'unload_regex' ) as $dataType ) {
|
||||
if ( isset( $wpacuGlobalDataArray[ $assetType ][ $dataType ] ) && ! empty( $wpacuGlobalDataArray[ $assetType ][ $dataType ] ) && array_key_exists($assetHandle, $wpacuGlobalDataArray[ $assetType ][ $dataType ]) ) {
|
||||
unset( $wpacuGlobalDataArray[ $assetType ][ $dataType ][ $assetHandle ]);
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption(
|
||||
WPACU_PLUGIN_ID . '_global_data',
|
||||
wp_json_encode( Misc::filterList( $wpacuGlobalDataArray ) )
|
||||
);
|
||||
}
|
||||
}
|
299
wp-content/plugins/wp-asset-clean-up/classes/Menu.php
Normal file
299
wp-content/plugins/wp-asset-clean-up/classes/Menu.php
Normal file
@ -0,0 +1,299 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class Menu
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Menu
|
||||
{
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
public static $allMenuPages = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $_capability = 'administrator';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $_slug;
|
||||
|
||||
/**
|
||||
* Menu constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::$allMenuPages = array(
|
||||
WPACU_PLUGIN_ID . '_getting_started',
|
||||
WPACU_PLUGIN_ID . '_settings',
|
||||
WPACU_PLUGIN_ID . '_assets_manager',
|
||||
WPACU_PLUGIN_ID . '_plugins_manager',
|
||||
WPACU_PLUGIN_ID . '_bulk_unloads',
|
||||
WPACU_PLUGIN_ID . '_overview',
|
||||
WPACU_PLUGIN_ID . '_tools',
|
||||
WPACU_PLUGIN_ID . '_license',
|
||||
WPACU_PLUGIN_ID . '_get_help',
|
||||
WPACU_PLUGIN_ID . '_go_pro'
|
||||
);
|
||||
|
||||
self::$_slug = WPACU_PLUGIN_ID . '_getting_started';
|
||||
|
||||
add_action('admin_menu', array($this, 'activeMenu'));
|
||||
|
||||
if (isset($_GET['page']) && $_GET['page'] === WPACU_PLUGIN_ID . '_go_pro') {
|
||||
header('Location: '.apply_filters('wpacu_go_pro_affiliate_link', WPACU_PLUGIN_GO_PRO_URL.'?utm_source=plugin_go_pro'));
|
||||
exit();
|
||||
}
|
||||
|
||||
add_filter( 'post_row_actions', array($this, 'editPostRowActions'), 10, 2 );
|
||||
add_filter( 'page_row_actions', array($this, 'editPostRowActions'), 10, 2 );
|
||||
|
||||
add_action('admin_page_access_denied', array($this, 'pluginPagesAccessDenied'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function activeMenu()
|
||||
{
|
||||
// User should be of 'administrator' role and allowed to activate plugins
|
||||
if (! self::userCanManageAssets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_menu_page(
|
||||
WPACU_PLUGIN_TITLE,
|
||||
WPACU_PLUGIN_TITLE,
|
||||
self::getAccessCapability(),
|
||||
self::$_slug,
|
||||
array(new Info, 'gettingStarted'),
|
||||
WPACU_PLUGIN_URL.'/assets/icons/icon-asset-cleanup.png'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Settings', 'wp-asset-clean-up'),
|
||||
__('Settings', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_settings',
|
||||
array(new Settings, 'settingsPage')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('CSS/JS Manager', 'wp-asset-clean-up'),
|
||||
__('CSS/JS Manager', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_assets_manager',
|
||||
array(new AssetsPagesManager, 'renderPage')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Plugins Manager', 'wp-asset-clean-up'),
|
||||
__('Plugins Manager', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_plugins_manager',
|
||||
array(new PluginsManager, 'page')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Bulk Changes', 'wp-asset-clean-up'),
|
||||
__('Bulk Changes', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_bulk_unloads',
|
||||
array(new BulkChanges, 'pageBulkUnloads')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Overview', 'wp-asset-clean-up'),
|
||||
__('Overview', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_overview',
|
||||
array(new Overview, 'pageOverview')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Tools', 'wp-asset-clean-up'),
|
||||
__('Tools', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_tools',
|
||||
array(new Tools, 'toolsPage')
|
||||
);
|
||||
|
||||
// License Page
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('License', 'wp-asset-clean-up'),
|
||||
__('License', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_license',
|
||||
array(new Info, 'license')
|
||||
);
|
||||
|
||||
// Get Help | Support Page
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Help', 'wp-asset-clean-up'),
|
||||
__('Help', 'wp-asset-clean-up'),
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_get_help',
|
||||
array(new Info, 'help')
|
||||
);
|
||||
|
||||
// [wpacu_lite]
|
||||
// Upgrade to "Go Pro" | Redirects to sale page
|
||||
add_submenu_page(
|
||||
self::$_slug,
|
||||
__('Go Pro', 'wp-asset-clean-up'),
|
||||
__('Go Pro', 'wp-asset-clean-up') . ' <span style="font-size: 16px; color: inherit;" class="dashicons dashicons-star-filled"></span>',
|
||||
self::getAccessCapability(),
|
||||
WPACU_PLUGIN_ID . '_go_pro',
|
||||
function() {}
|
||||
);
|
||||
// [/wpacu_lite]
|
||||
|
||||
// Add "Asset CleanUp Pro" Settings Link to the main "Settings" menu within the Dashboard
|
||||
// For easier navigation
|
||||
$GLOBALS['submenu']['options-general.php'][] = array(
|
||||
WPACU_PLUGIN_TITLE,
|
||||
self::getAccessCapability(),
|
||||
esc_url(admin_url( 'admin.php?page=' . WPACU_PLUGIN_ID . '_settings')),
|
||||
WPACU_PLUGIN_TITLE,
|
||||
);
|
||||
|
||||
// Rename first item from the menu which has the same title as the menu page
|
||||
$GLOBALS['submenu'][self::$_slug][0][0] = esc_attr__('Getting Started', 'wp-asset-clean-up');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function userCanManageAssets()
|
||||
{
|
||||
if (is_super_admin()) {
|
||||
return true; // For security reasons, super admins will always be able to access the plugin's settings
|
||||
}
|
||||
|
||||
// Has self::$_capability been changed? Just user current_user_can()
|
||||
if (self::getAccessCapability() !== self::$_capability) {
|
||||
return current_user_can(self::getAccessCapability());
|
||||
}
|
||||
|
||||
// self::$_capability default value: "administrator"
|
||||
return current_user_can(self::getAccessCapability());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPluginPage()
|
||||
{
|
||||
return isset($_GET['page']) && in_array($_GET['page'], self::$allMenuPages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Here self::$_capability can be overridden
|
||||
*
|
||||
* @return mixed|void
|
||||
*/
|
||||
public static function getAccessCapability()
|
||||
{
|
||||
return apply_filters('wpacu_access_role', self::$_capability);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $actions
|
||||
* @param $post
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function editPostRowActions($actions, $post)
|
||||
{
|
||||
// Check for your post type.
|
||||
if ( $post->post_type === 'post' ) {
|
||||
$wpacuFor = 'posts';
|
||||
} elseif ( $post->post_type === 'page' ) {
|
||||
$wpacuFor = 'pages';
|
||||
} elseif ( $post->post_type === 'attachment' ) {
|
||||
$wpacuFor = 'media-attachment';
|
||||
} else {
|
||||
$wpacuFor = 'custom-post-types';
|
||||
}
|
||||
|
||||
$postTypeObject = get_post_type_object($post->post_type);
|
||||
|
||||
if ( ! (isset($postTypeObject->public) && $postTypeObject->public == 1) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
if ( ! in_array(get_post_status($post), array('publish', 'private')) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
// Do not show the management link to specific post types that are marked as "public", but not relevant such as "ct_template" from Oxygen Builder
|
||||
if (in_array($post->post_type, MetaBoxes::$noMetaBoxesForPostTypes)) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
// Build your links URL.
|
||||
$url = esc_url(admin_url( 'admin.php?page=wpassetcleanup_assets_manager' ));
|
||||
|
||||
// Maybe put in some extra arguments based on the post status.
|
||||
$edit_link = add_query_arg(
|
||||
array(
|
||||
'wpacu_for' => $wpacuFor,
|
||||
'wpacu_post_id' => $post->ID
|
||||
), $url
|
||||
);
|
||||
|
||||
// Only show it to the user that has "administrator" access, and it's in the following list (if a certain list of admins is provided)
|
||||
// "Settings" -> "Plugin Usage Preferences" -> "Allow managing assets to:"
|
||||
if (self::userCanManageAssets() && Main::currentUserCanViewAssetsList()) {
|
||||
/*
|
||||
* You can reset the default $actions with your own array, or simply merge them
|
||||
* here I want to rewrite my Edit link, remove the Quick-link, and introduce a
|
||||
* new link 'Copy'
|
||||
*/
|
||||
$actions['wpacu_manage_assets'] = sprintf( '<a href="%1$s">%2$s</a>',
|
||||
esc_url( $edit_link ),
|
||||
esc_html( __( 'Manage CSS & JS', 'wp-asset-clean-up' ) )
|
||||
);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message to show if the user does not have self::$_capability role and tries to access a plugin's page
|
||||
*/
|
||||
public function pluginPagesAccessDenied()
|
||||
{
|
||||
if ( ! self::isPluginPage() ) {
|
||||
// Not an Asset CleanUp page
|
||||
return;
|
||||
}
|
||||
|
||||
$userMeta = get_userdata(get_current_user_id());
|
||||
$userRoles = $userMeta->roles;
|
||||
|
||||
wp_die(
|
||||
__('Sorry, you are not allowed to access this page.').'<br /><br />'.
|
||||
sprintf(__('Asset CleanUp requires "%s" role and the ability to activate plugins in order to access its pages.', 'wp-asset-clean-up'), '<span style="color: green; font-weight: bold;">'.self::getAccessCapability().'</span>').'<br />'.
|
||||
sprintf(__('Your current role(s): <strong>%s</strong>', 'wp-asset-clean-up'), implode(', ', $userRoles)).'<br /><br />'.
|
||||
__('The value (in green color) can be changed if you use the following snippet in functions.php (within your theme/child theme or a custom plugin):').'<br />'.
|
||||
'<p style="margin: -10px 0 0;"><code style="background: #f2f3ea; padding: 5px;">add_filter(\'wpacu_access_role\', function($role) { return \'your_role_here\'; });</code></p>'.
|
||||
'<p>If the snippet is not used, it will default to "administrator".</p>'.
|
||||
'<p>Possible values: <strong>manage_options</strong>, <strong>activate_plugins</strong>, <strong>manager</strong> etc.</p>'.
|
||||
'<p>Read more: <a target="_blank" href="https://wordpress.org/support/article/roles-and-capabilities/#summary-of-roles">https://wordpress.org/support/article/roles-and-capabilities/#summary-of-roles</a></p>',
|
||||
403
|
||||
);
|
||||
}
|
||||
}
|
348
wp-content/plugins/wp-asset-clean-up/classes/MetaBoxes.php
Normal file
348
wp-content/plugins/wp-asset-clean-up/classes/MetaBoxes.php
Normal file
@ -0,0 +1,348 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class MetaBoxes
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class MetaBoxes
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $noMetaBoxesForPostTypes = array(
|
||||
// Oxygen Page Builder
|
||||
'ct_template',
|
||||
'oxy_user_library',
|
||||
|
||||
// Themify Page Builder (Layout & Layout Part)
|
||||
'tbuilder_layout',
|
||||
'tbuilder_layout_part',
|
||||
|
||||
// "Popup Maker" plugin
|
||||
'popup',
|
||||
'popup_theme',
|
||||
|
||||
// "Popup Builder" plugin
|
||||
'popupbuilder',
|
||||
|
||||
// "Datafeedr Product Sets" plugin
|
||||
'datafeedr-productset',
|
||||
|
||||
// Elementor
|
||||
'elementor_library'
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function initMetaBox($type)
|
||||
{
|
||||
if ( ! Menu::userCanManageAssets() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
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; // the current logged-in admin is not in the list of "Allow managing assets to:"
|
||||
}
|
||||
}
|
||||
|
||||
if ($type === 'manage_page_assets') {
|
||||
add_action( 'add_meta_boxes', array( $this, 'addAssetManagerMetaBox' ), 11 );
|
||||
add_action( 'add_meta_boxes', array( $this, 'keepAssetManagerMetaBoxOnTheLeftSide' ), 1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $postType
|
||||
*/
|
||||
public function addAssetManagerMetaBox($postType)
|
||||
{
|
||||
$obj = $this->showMetaBoxes($postType);
|
||||
|
||||
if (isset($obj->public) && $obj->public > 0) {
|
||||
add_meta_box(
|
||||
WPACU_PLUGIN_ID . '_asset_list',
|
||||
WPACU_PLUGIN_TITLE.': '.__('CSS & JavaScript Manager / Page Options', 'wp-asset-clean-up'),
|
||||
array($this, 'renderAssetManagerMetaBoxContent'),
|
||||
$postType,
|
||||
apply_filters('wpacu_asset_list_meta_box_context', 'normal'),
|
||||
apply_filters('wpacu_asset_list_meta_box_priority', 'high')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes, users are moving by mistake the meta box to the right side which is not desirable
|
||||
* and have difficulties moving it back, thus, this method moves it back to the left (normal) side
|
||||
*
|
||||
* @param $postType
|
||||
*/
|
||||
public function keepAssetManagerMetaBoxOnTheLeftSide($postType)
|
||||
{
|
||||
$user = wp_get_current_user();
|
||||
|
||||
if (isset($user->ID) && $user->ID) {
|
||||
$userMetaBoxOption = get_user_option('meta-box-order_'.$postType, $user->ID );
|
||||
|
||||
if (isset($userMetaBoxOption['side'], $userMetaBoxOption['normal']) && strpos($userMetaBoxOption['side'], WPACU_PLUGIN_ID . '_asset_list') !== false) {
|
||||
// Remove it from the side list
|
||||
if (strpos($userMetaBoxOption['side'], ',') !== false) {
|
||||
$allSideMetaBoxes = explode(',', $userMetaBoxOption['side']);
|
||||
|
||||
foreach ($allSideMetaBoxes as $sideMetaBoxIndex => $sideMetaBoxName) {
|
||||
if ($sideMetaBoxName === WPACU_PLUGIN_ID . '_asset_list') {
|
||||
unset($allSideMetaBoxes[$sideMetaBoxIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
$userMetaBoxOption['side'] = implode(',', array_unique($allSideMetaBoxes));
|
||||
} else {
|
||||
$userMetaBoxOption['side'] = str_replace(WPACU_PLUGIN_ID . '_asset_list', '', $userMetaBoxOption['side']);
|
||||
}
|
||||
|
||||
// Move it back to the normal one
|
||||
if (strpos($userMetaBoxOption['normal'], ',') !== false) {
|
||||
$allNormalMetaBoxes = explode( ',', $userMetaBoxOption['normal'] );
|
||||
$allNormalMetaBoxes[] = WPACU_PLUGIN_ID . '_asset_list';
|
||||
$userMetaBoxOption['normal'] = implode(',', array_unique($allNormalMetaBoxes));
|
||||
} elseif ($userMetaBoxOption['normal'] !== '') {
|
||||
$userMetaBoxOption['normal'] .= ','.WPACU_PLUGIN_ID . '_asset_list';
|
||||
} elseif ($userMetaBoxOption['normal'] === '') {
|
||||
$userMetaBoxOption['normal'] .= WPACU_PLUGIN_ID . '_asset_list';
|
||||
}
|
||||
|
||||
update_user_option($user->ID, 'meta-box-order_'.$postType, $userMetaBoxOption, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $postType
|
||||
*/
|
||||
public function addPageOptionsMetaBox($postType)
|
||||
{
|
||||
global $post;
|
||||
|
||||
if (self::isMediaWithPermalinkDeactivated($post)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$obj = $this->showMetaBoxes($postType);
|
||||
|
||||
if (isset($obj->public) && $obj->public > 0) {
|
||||
add_meta_box(
|
||||
WPACU_PLUGIN_ID . '_page_options',
|
||||
WPACU_PLUGIN_TITLE.': '.__('Options', 'wp-asset-clean-up'),
|
||||
array($this, 'renderPageOptionsMetaBoxContent'),
|
||||
$postType,
|
||||
apply_filters('wpacu_page_options_meta_box_context', 'side'),
|
||||
apply_filters('wpacu_page_options_meta_box_priority', 'high')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is triggered only in the Edit Mode Dashboard View
|
||||
*/
|
||||
public function renderAssetManagerMetaBoxContent()
|
||||
{
|
||||
global $post;
|
||||
|
||||
if ($post->ID === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = array('status' => 1);
|
||||
|
||||
$postId = (isset($post->ID) && $post->ID > 0) ? $post->ID : 0;
|
||||
|
||||
$isListFetchable = true;
|
||||
|
||||
if (! Main::instance()->settings['dashboard_show']) {
|
||||
$isListFetchable = false;
|
||||
$data['status'] = 2; // "Manage within Dashboard" is disabled in plugin's settings
|
||||
} elseif ($postId < 1 || ! in_array(get_post_status($postId), array('publish', 'private'))) {
|
||||
$data['status'] = 3; // "draft", "auto-draft" post (it has to be published)
|
||||
$isListFetchable = false;
|
||||
}
|
||||
|
||||
if (self::isMediaWithPermalinkDeactivated($post)) {
|
||||
$isListFetchable = false;
|
||||
$data['status'] = 4; // "Redirect attachment URLs to the attachment itself?" is enabled in "Yoast SEO" -> "Media"
|
||||
}
|
||||
|
||||
if ($isListFetchable) {
|
||||
$data['fetch_url'] = Misc::getPageUrl($postId);
|
||||
|
||||
switch (assetCleanUpHasNoLoadMatches($data['fetch_url'])) {
|
||||
case 'is_set_in_settings':
|
||||
// The rules from "Settings" -> "Plugin Usage Preferences" -> "Do not load the plugin on certain pages" will be checked
|
||||
$data['status'] = 5;
|
||||
$isListFetchable = false;
|
||||
break;
|
||||
|
||||
case 'is_set_in_page':
|
||||
// The following option from "Page Options" (within the CSS/JS manager of the targeted page) is set: "Do not load Asset CleanUp Pro on this page (this will disable any functionality of the plugin)"
|
||||
$data['status'] = 6;
|
||||
$isListFetchable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$data['is_list_fetchable'] = $isListFetchable;
|
||||
$data['fetch_assets_on_click'] = false;
|
||||
|
||||
if ($isListFetchable) {
|
||||
if (Main::instance()->settings['assets_list_show_status'] === 'fetch_on_click') {
|
||||
$data['fetch_assets_on_click'] = true;
|
||||
}
|
||||
|
||||
$data['dom_get_type'] = Main::instance()->settings['dom_get_type'];
|
||||
}
|
||||
|
||||
$data['post_id'] = $postId;
|
||||
|
||||
Main::instance()->parseTemplate('meta-box', $data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is triggered only in the Edit Mode Dashboard View
|
||||
* Valid for posts, pages (a page can also be set as the homepage), custom post types
|
||||
*/
|
||||
public function renderPageOptionsMetaBoxContent()
|
||||
{
|
||||
$data = array('page_options' => self::getPageOptions());
|
||||
|
||||
Main::instance()->parseTemplate('meta-box-side-page-options', $data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
* @param string $type
|
||||
* @return array|mixed|object
|
||||
*/
|
||||
public static function getPageOptions($postId = 0, $type = 'post')
|
||||
{
|
||||
if ($type === 'post' || $postId > 0) {
|
||||
if ( $postId < 1 ) {
|
||||
global $post;
|
||||
$postId = (int) $post->ID;
|
||||
}
|
||||
|
||||
if ( $postId > 1 ) {
|
||||
$metaPageOptionsJson = get_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_page_options', true );
|
||||
return @json_decode( $metaPageOptionsJson, ARRAY_A );
|
||||
}
|
||||
} elseif ($type === 'front_page') { // e.g. the latest posts, not a chosen page ID (that's when $type as 'post' is used)
|
||||
$globalPageOptions = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
|
||||
if ($globalPageOptions) {
|
||||
$globalPageOptionsList = @json_decode( $globalPageOptions, true );
|
||||
|
||||
if ( isset( $globalPageOptionsList['page_options']['homepage'] ) && ! empty( $globalPageOptionsList['page_options']['homepage'] ) ) {
|
||||
return $globalPageOptionsList['page_options']['homepage'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasNoFrontendOptimizationPageOption()
|
||||
{
|
||||
$isSingularPage = defined('WPACU_CURRENT_PAGE_ID') && WPACU_CURRENT_PAGE_ID > 0 && is_singular();
|
||||
|
||||
if ($isSingularPage || Misc::isHomePage()) {
|
||||
if ($isSingularPage) {
|
||||
$pageOptions = self::getPageOptions( WPACU_CURRENT_PAGE_ID ); // Singular page
|
||||
} else {
|
||||
$pageOptions = self::getPageOptions(0, 'front_page'); // Home page
|
||||
}
|
||||
|
||||
if (isset($pageOptions['no_assets_settings']) && $pageOptions['no_assets_settings']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function hideMetaBoxesForPostTypes()
|
||||
{
|
||||
$allValues = self::$noMetaBoxesForPostTypes;
|
||||
|
||||
$hideForChosenPostTypes = Main::instance()->settings['hide_meta_boxes_for_post_types'];
|
||||
|
||||
if (! empty($hideForChosenPostTypes)) {
|
||||
foreach ($hideForChosenPostTypes as $chosenPostType) {
|
||||
$allValues[] = trim($chosenPostType);
|
||||
}
|
||||
}
|
||||
|
||||
return $allValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to show any Asset CleanUp (Pro) meta boxes, depending on the post type
|
||||
*
|
||||
* @param $postType
|
||||
* @return bool|object
|
||||
*/
|
||||
public function showMetaBoxes($postType)
|
||||
{
|
||||
$obj = get_post_type_object($postType);
|
||||
|
||||
// These are not public pages that are loading CSS/JS
|
||||
// e.g. URI request ending in '/ct_template/inner-content/'
|
||||
if (isset($obj->name) && $obj->name && in_array($obj->name, self::hideMetaBoxesForPostTypes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($_GET['post'], $obj->name) && $_GET['post'] && $obj->name) {
|
||||
$permalinkStructure = get_option( 'permalink_structure' );
|
||||
$postPermalink = get_permalink( $_GET['post'] );
|
||||
|
||||
if (strpos($permalinkStructure, '%postname%') !== false && strpos($postPermalink, '/?'.$obj->name.'=')) {
|
||||
// Doesn't have the right permalink; Showing any Asset CleanUp (Lite or Pro) options is not relevant
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $post
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMediaWithPermalinkDeactivated($post = '')
|
||||
{
|
||||
if ($post === '') {
|
||||
$postTypeToCheck = 'attachment';
|
||||
} else {
|
||||
$postTypeToCheck = get_post_type($post->ID);
|
||||
}
|
||||
|
||||
if ('attachment' === $postTypeToCheck && method_exists('WPSEO_Options', 'get')) {
|
||||
try {
|
||||
if (\WPSEO_Options::get( 'disable-attachment' ) === true) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
2095
wp-content/plugins/wp-asset-clean-up/classes/Misc.php
Normal file
2095
wp-content/plugins/wp-asset-clean-up/classes/Misc.php
Normal file
File diff suppressed because it is too large
Load Diff
775
wp-content/plugins/wp-asset-clean-up/classes/ObjectCache.php
Normal file
775
wp-content/plugins/wp-asset-clean-up/classes/ObjectCache.php
Normal file
@ -0,0 +1,775 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* NOTE: This is from the original core file located /wp-includes/class-wp-object-cache.php
|
||||
* Avoid the WordPress core $wp_object_cache global variable which is sometimes altered by 3rd party plugins
|
||||
* This would make this plugin compatible with plugins such as "Redis Object Cache"
|
||||
*
|
||||
* Object Cache API: ObjectCache class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Cache
|
||||
* @since 5.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class that implements an object cache.
|
||||
*
|
||||
* The WordPress Object Cache is used to save on trips to the database. The
|
||||
* Object Cache stores all the cache data to memory and makes the cache
|
||||
* contents available by using a key, which is used to name and later retrieve
|
||||
* the cache contents.
|
||||
*
|
||||
* The Object Cache can be replaced by other caching mechanisms by placing files
|
||||
* in the wp-content folder which is looked at in wp-settings. If that file
|
||||
* exists, then this file will not be included.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class ObjectCache {
|
||||
|
||||
/**
|
||||
* Holds the cached objects.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @var array
|
||||
*/
|
||||
private $cache = array();
|
||||
|
||||
/**
|
||||
* The amount of times the cache data was already stored in the cache.
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @var int
|
||||
*/
|
||||
public $cache_hits = 0;
|
||||
|
||||
/**
|
||||
* Amount of times the cache did not have the request in cache.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @var int
|
||||
*/
|
||||
public $cache_misses = 0;
|
||||
|
||||
/**
|
||||
* List of global cache groups.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $global_groups = array();
|
||||
|
||||
/**
|
||||
* The blog prefix to prepend to keys in non-global groups.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @var string
|
||||
*/
|
||||
private $blog_prefix;
|
||||
|
||||
/**
|
||||
* Holds the value of is_multisite().
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @var bool
|
||||
*/
|
||||
private $multisite;
|
||||
|
||||
/**
|
||||
* @var string|void
|
||||
*/
|
||||
public static $objNotInitErrorMsg;
|
||||
|
||||
/**
|
||||
* Sets up object properties; PHP 5 style constructor.
|
||||
*
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public function __construct() {
|
||||
self::$objNotInitErrorMsg = __('Asset CleanUp\'s object cache is not valid (from method "[method]").', 'wp-asset-clean-up');
|
||||
|
||||
$this->multisite = is_multisite();
|
||||
$this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes private properties readable for backward compatibility.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $name Property to get.
|
||||
* @return mixed Property.
|
||||
*/
|
||||
public function __get( $name ) {
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes private properties settable for backward compatibility.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $name Property to set.
|
||||
* @param mixed $value Property value.
|
||||
* @return mixed Newly-set property.
|
||||
*/
|
||||
public function __set( $name, $value ) {
|
||||
return $this->$name = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes private properties checkable for backward compatibility.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $name Property to check if set.
|
||||
* @return bool Whether the property is set.
|
||||
*/
|
||||
public function __isset( $name ) {
|
||||
return isset( $this->$name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes private properties un-settable for backward compatibility.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $name Property to unset.
|
||||
*/
|
||||
public function __unset( $name ) {
|
||||
unset( $this->$name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data to the cache if it doesn't already exist.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @uses ObjectCache::_exists() Checks to see if the cache already has data.
|
||||
* @uses ObjectCache::set() Sets the data after the checking the cache
|
||||
* contents existence.
|
||||
*
|
||||
* @param int|string $key What to call the contents in the cache.
|
||||
* @param mixed $data The contents to store in the cache.
|
||||
* @param string $group Optional. Where to group the cache contents. Default 'default'.
|
||||
* @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
|
||||
* @return bool True on success, false if cache key and group already exist.
|
||||
*/
|
||||
public function add( $key, $data, $group = 'default', $expire = 0 ) {
|
||||
if ( wp_suspend_cache_addition() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
$id = $key;
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$id = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( $this->_exists( $id, $group ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->set( $key, $data, $group, (int) $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of global cache groups.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array $groups List of groups that are global.
|
||||
*/
|
||||
public function add_global_groups( $groups ) {
|
||||
$groups = (array) $groups;
|
||||
|
||||
$groups = array_fill_keys( $groups, true );
|
||||
$this->global_groups = array_merge( $this->global_groups, $groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements numeric cache item's value.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param int|string $key The cache key to decrement.
|
||||
* @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
|
||||
* @param string $group Optional. The group the key is in. Default 'default'.
|
||||
* @return int|false The item's new value on success, false on failure.
|
||||
*/
|
||||
public function decr( $key, $offset = 1, $group = 'default' ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$key = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( ! $this->_exists( $key, $group ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
|
||||
$this->cache[ $group ][ $key ] = 0;
|
||||
}
|
||||
|
||||
$offset = (int) $offset;
|
||||
|
||||
$this->cache[ $group ][ $key ] -= $offset;
|
||||
|
||||
if ( $this->cache[ $group ][ $key ] < 0 ) {
|
||||
$this->cache[ $group ][ $key ] = 0;
|
||||
}
|
||||
|
||||
return $this->cache[ $group ][ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the contents of the cache key in the group.
|
||||
*
|
||||
* If the cache key does not exist in the group, then nothing will happen.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param int|string $key What the contents in the cache are called.
|
||||
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
|
||||
* @param bool $deprecated Optional. Unused. Default false.
|
||||
* @return bool False if the contents weren't deleted and true on success.
|
||||
*/
|
||||
public function delete( $key, $group = 'default', $deprecated = false ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$key = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( ! $this->_exists( $key, $group ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unset( $this->cache[ $group ][ $key ] );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the object cache of all data.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return true Always returns true.
|
||||
*/
|
||||
public function flush() {
|
||||
$this->cache = array();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the cache contents, if it exists.
|
||||
*
|
||||
* The contents will be first attempted to be retrieved by searching by the
|
||||
* key in the cache group. If the cache is hit (success) then the contents
|
||||
* are returned.
|
||||
*
|
||||
* On failure, the number of cache misses will be incremented.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param int|string $key What the contents in the cache are called.
|
||||
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
|
||||
* @param bool $force Optional. Unused. Whether to force a refetch rather than relying on the local
|
||||
* cache. Default false.
|
||||
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
|
||||
* Disambiguates a return of false, a storable value. Default null.
|
||||
* @return mixed|false The cache contents on success, false on failure to retrieve contents.
|
||||
*/
|
||||
public function get( $key, $group = 'default', $force = false, &$found = null ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$key = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( $this->_exists( $key, $group ) ) {
|
||||
$found = true;
|
||||
$this->cache_hits += 1;
|
||||
if ( is_object( $this->cache[ $group ][ $key ] ) ) {
|
||||
return clone $this->cache[ $group ][ $key ];
|
||||
} else {
|
||||
return $this->cache[ $group ][ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
$found = false;
|
||||
$this->cache_misses += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments numeric cache item's value.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param int|string $key The cache key to increment
|
||||
* @param int $offset Optional. The amount by which to increment the item's value. Default 1.
|
||||
* @param string $group Optional. The group the key is in. Default 'default'.
|
||||
* @return int|false The item's new value on success, false on failure.
|
||||
*/
|
||||
public function incr( $key, $offset = 1, $group = 'default' ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$key = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( ! $this->_exists( $key, $group ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
|
||||
$this->cache[ $group ][ $key ] = 0;
|
||||
}
|
||||
|
||||
$offset = (int) $offset;
|
||||
|
||||
$this->cache[ $group ][ $key ] += $offset;
|
||||
|
||||
if ( $this->cache[ $group ][ $key ] < 0 ) {
|
||||
$this->cache[ $group ][ $key ] = 0;
|
||||
}
|
||||
|
||||
return $this->cache[ $group ][ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the contents in the cache, if contents already exist.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::set()
|
||||
*
|
||||
* @param int|string $key What to call the contents in the cache.
|
||||
* @param mixed $data The contents to store in the cache.
|
||||
* @param string $group Optional. Where to group the cache contents. Default 'default'.
|
||||
* @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
|
||||
* @return bool False if not exists, true if contents were replaced.
|
||||
*/
|
||||
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
$id = $key;
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$id = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( ! $this->_exists( $id, $group ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->set( $key, $data, $group, (int) $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets cache keys.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @deprecated 3.5.0 Use switch_to_blog()
|
||||
* @see switch_to_blog()
|
||||
*/
|
||||
public function reset() {
|
||||
_deprecated_function( __FUNCTION__, '3.5.0', 'switch_to_blog()' );
|
||||
|
||||
// Clear out non-global caches since the blog ID has changed.
|
||||
foreach ( array_keys( $this->cache ) as $group ) {
|
||||
if ( ! isset( $this->global_groups[ $group ] ) ) {
|
||||
unset( $this->cache[ $group ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data contents into the cache.
|
||||
*
|
||||
* The cache contents are grouped by the $group parameter followed by the
|
||||
* $key. This allows for duplicate ids in unique groups. Therefore, naming of
|
||||
* the group should be used with care and should follow normal function
|
||||
* naming guidelines outside of core WordPress usage.
|
||||
*
|
||||
* The $expire parameter is not used, because the cache will automatically
|
||||
* expire for each time a page is accessed and PHP finishes. The method is
|
||||
* more for cache plugins which use files.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param int|string $key What to call the contents in the cache.
|
||||
* @param mixed $data The contents to store in the cache.
|
||||
* @param string $group Optional. Where to group the cache contents. Default 'default'.
|
||||
* @param int $expire Not Used.
|
||||
* @return true Always returns true.
|
||||
*/
|
||||
public function set( $key, $data, $group = 'default', $expire = 0 ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
|
||||
$key = $this->blog_prefix . $key;
|
||||
}
|
||||
|
||||
if ( is_object( $data ) ) {
|
||||
$data = clone $data;
|
||||
}
|
||||
|
||||
$this->cache[ $group ][ $key ] = $data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the stats of the caching.
|
||||
*
|
||||
* Gives the cache hits, and cache misses. Also prints every cached group,
|
||||
* key and the data.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function stats() {
|
||||
echo '<p>';
|
||||
echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
|
||||
echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
|
||||
echo '</p>';
|
||||
echo '<ul>';
|
||||
foreach ( $this->cache as $group => $cache ) {
|
||||
echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the internal blog ID.
|
||||
*
|
||||
* This changes the blog ID used to create keys in blog specific groups.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param int $blog_id Blog ID.
|
||||
*/
|
||||
public function switch_to_blog( $blog_id ) {
|
||||
$blog_id = (int) $blog_id;
|
||||
$this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves as a utility function to determine whether a key exists in the cache.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param int|string $key Cache key to check for existence.
|
||||
* @param string $group Cache group for the key existence check.
|
||||
* @return bool Whether the key exists in the cache for the given group.
|
||||
*/
|
||||
protected function _exists( $key, $group ) {
|
||||
return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [START] Functions to call (reference: /wp-includes/cache.php)
|
||||
*/
|
||||
/**
|
||||
* Adds data to the cache, if the cache key doesn't already exist.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::add()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The cache key to use for retrieval later.
|
||||
* @param mixed $data The data to add to the cache.
|
||||
* @param string $group Optional. The group to add the cache to. Enables the same key
|
||||
* to be used across groups. Default empty.
|
||||
* @param int $expire Optional. When the cache data should expire, in seconds.
|
||||
* Default 0 (no expiration).
|
||||
* @return bool True on success, false if cache key and group already exist.
|
||||
*/
|
||||
public static function wpacu_cache_add( $key, $data, $group = '', $expire = 0 ) {
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->add( $key, $data, $group, (int) $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cache.
|
||||
*
|
||||
* This function has ceased to do anything since WordPress 2.5. The
|
||||
* functionality was removed along with the rest of the persistent cache.
|
||||
*
|
||||
* This does not mean that plugins can't implement this function when they need
|
||||
* to make sure that the cache is cleaned up after WordPress no longer needs it.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return true Always returns true.
|
||||
*/
|
||||
public static function wpacu_cache_close() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements numeric cache item's value.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @see ObjectCache::decr()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The cache key to decrement.
|
||||
* @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
|
||||
* @param string $group Optional. The group the key is in. Default empty.
|
||||
* @return int|false The item's new value on success, false on failure.
|
||||
*/
|
||||
public static function wpacu_cache_decr( $key, $offset = 1, $group = '' ) {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->decr( $key, $offset, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cache contents matching key and group.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::delete()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key What the contents in the cache are called.
|
||||
* @param string $group Optional. Where the cache contents are grouped. Default empty.
|
||||
* @return bool True on successful removal, false on failure.
|
||||
*/
|
||||
public static function wpacu_cache_delete( $key, $group = '' ) {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->delete( $key, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all cache items.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::flush()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
public static function wpacu_cache_flush() {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the cache contents from the cache by key and group.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::get()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The key under which the cache contents are stored.
|
||||
* @param string $group Optional. Where the cache contents are grouped. Default empty.
|
||||
* @param bool $force Optional. Whether to force an update of the local cache from the persistent
|
||||
* cache. Default false.
|
||||
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
|
||||
* Disambiguates a return of false, a storable value. Default null.
|
||||
* @return bool|mixed False on failure to retrieve contents or the cache
|
||||
* contents on success
|
||||
*/
|
||||
public static function wpacu_cache_get( $key, $group = '', $force = false, &$found = null ) {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->get( $key, $group, $force, $found );
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment numeric cache item's value
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @see ObjectCache::incr()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The key for the cache contents that should be incremented.
|
||||
* @param int $offset Optional. The amount by which to increment the item's value. Default 1.
|
||||
* @param string $group Optional. The group the key is in. Default empty.
|
||||
* @return int|false The item's new value on success, false on failure.
|
||||
*/
|
||||
public static function wpacu_cache_incr( $key, $offset = 1, $group = '' ) {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->incr( $key, $offset, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up Object Cache Global and assigns it.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @global ObjectCache $wpacu_object_cache
|
||||
*/
|
||||
public static function wpacu_cache_init() {
|
||||
$GLOBALS['wpacu_object_cache'] = new self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the contents of the cache with new data.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::replace()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The key for the cache data that should be replaced.
|
||||
* @param mixed $data The new data to store in the cache.
|
||||
* @param string $group Optional. The group for the cache data that should be replaced.
|
||||
* Default empty.
|
||||
* @param int $expire Optional. When to expire the cache contents, in seconds.
|
||||
* Default 0 (no expiration).
|
||||
* @return bool False if original value does not exist, true if contents were replaced
|
||||
*/
|
||||
public static function wpacu_cache_replace( $key, $data, $group = '', $expire = 0 ) {
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->replace( $key, $data, $group, (int) $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the data to the cache.
|
||||
*
|
||||
* Differs from ObjectCache::wpacu_cache_add() and wp_cache_replace() in that it will always write data.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @see ObjectCache::set()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int|string $key The cache key to use for retrieval later.
|
||||
* @param mixed $data The contents to store in the cache.
|
||||
* @param string $group Optional. Where to group the cache contents. Enables the same key
|
||||
* to be used across groups. Default empty.
|
||||
* @param int $expire Optional. When to expire the cache contents, in seconds.
|
||||
* Default 0 (no expiration).
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
public static function wpacu_cache_set( $key, $data, $group = '', $expire = 0 ) {
|
||||
global $wpacu_object_cache;
|
||||
|
||||
return $wpacu_object_cache->set( $key, $data, $group, (int) $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the internal blog ID.
|
||||
*
|
||||
* This changes the blog id used to create keys in blog specific groups.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @see ObjectCache::switch_to_blog()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param int $blog_id Site ID.
|
||||
*/
|
||||
public static function wpacu_cache_switch_to_blog( $blog_id ) {
|
||||
global $wpacu_object_cache;
|
||||
|
||||
$wpacu_object_cache->switch_to_blog( $blog_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a group or set of groups to the list of global groups.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*
|
||||
* @see ObjectCache::add_global_groups()
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*
|
||||
* @param string|array $groups A group or an array of groups to add.
|
||||
*/
|
||||
public static function wpacu_cache_add_global_groups( $groups ) {
|
||||
global $wpacu_object_cache;
|
||||
|
||||
$wpacu_object_cache->add_global_groups( $groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a group or set of groups to the list of non-persistent groups.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*
|
||||
* @param string|array $groups A group or an array of groups to add.
|
||||
*/
|
||||
public static function wpacu_cache_add_non_persistent_groups( $groups ) {
|
||||
// Default cache doesn't persist so nothing to do here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset internal cache keys and structures.
|
||||
*
|
||||
* If the cache back end uses global blog or site IDs as part of its cache keys,
|
||||
* this function instructs the back end to reset those keys and perform any cleanup
|
||||
* since blog or site IDs have changed since cache init.
|
||||
*
|
||||
* This function is deprecated. Use wp_cache_switch_to_blog() instead of this
|
||||
* function when preparing the cache for a blog switch. For clearing the cache
|
||||
* during unit tests, consider using wp_cache_init(). wp_cache_init() is not
|
||||
* recommended outside of unit tests as the performance penalty for using it is
|
||||
* high.
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @deprecated 3.5.0 ObjectCache::reset()
|
||||
* @see ObjectCache::reset()
|
||||
*
|
||||
* @global ObjectCache $wpacu_object_cache Object cache global instance.
|
||||
*/
|
||||
public static function wpacu_cache_reset() {
|
||||
_deprecated_function( __FUNCTION__, '3.5.0', 'ObjectCache::reset()' );
|
||||
|
||||
if ( ! self::isValidObjectCache() ) { error_log(str_replace('[method]', __METHOD__, self::$objNotInitErrorMsg)); return; }
|
||||
global $wpacu_object_cache;
|
||||
|
||||
$wpacu_object_cache->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main purpose: Avoid errors such as "PHP Fatal error: Uncaught Error: Call to a member function get() on null"
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidObjectCache()
|
||||
{
|
||||
global $wpacu_object_cache;
|
||||
return isset( $wpacu_object_cache ) && ! is_null( $wpacu_object_cache );
|
||||
}
|
||||
/**
|
||||
* [END] Functions to call (reference: /wp-includes/cache.php)
|
||||
*/
|
||||
}
|
@ -0,0 +1,627 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Menu;
|
||||
use WpAssetCleanUp\FileSystem;
|
||||
use WpAssetCleanUp\Misc;
|
||||
use WpAssetCleanUp\ObjectCache;
|
||||
use WpAssetCleanUp\Preloads;
|
||||
|
||||
/**
|
||||
* Class CombineCss
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class CombineCss
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $jsonStorageFile = 'css-combined{maybe-extra-info}.json';
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function doCombine($htmlSource)
|
||||
{
|
||||
if ( ! Misc::isDOMDocumentOn() ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
if ( ! self::proceedWithCssCombine() ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
global $wp_styles;
|
||||
$wpacuRegisteredStyles = $wp_styles->registered;
|
||||
|
||||
$storageJsonContents = array();
|
||||
$skipCache = false; // default
|
||||
|
||||
if (isset($_GET['wpacu_no_cache']) || (defined('WPACU_NO_CACHE') && WPACU_NO_CACHE === true)) {
|
||||
$skipCache = true;
|
||||
}
|
||||
|
||||
// If cache is not skipped, read the information from the cache as it's much faster
|
||||
if (! $skipCache) {
|
||||
// Speed up processing by getting the already existing final CSS file URI
|
||||
// This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
|
||||
$storageJsonContents = OptimizeCommon::getAssetCachedData( self::$jsonStorageFile, OptimizeCss::getRelPathCssCacheDir(), 'css' );
|
||||
}
|
||||
|
||||
// $uriToFinalCssFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathCssCacheDir()
|
||||
// which is usually "wp-content/cache/asset-cleanup/css/"
|
||||
|
||||
if ( $skipCache || empty($storageJsonContents) ) {
|
||||
$storageJsonContentsToSave = array();
|
||||
|
||||
/*
|
||||
* NO CACHING? Parse the DOM
|
||||
*/
|
||||
// Nothing in the database records or the retrieved cached file does not exist?
|
||||
OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
|
||||
|
||||
$storageJsonContents = array();
|
||||
|
||||
$domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'combineCss');
|
||||
|
||||
foreach (array('head', 'body') as $docLocationTag) {
|
||||
$combinedUriPathsGroup = $localAssetsPathsGroup = $linkHrefsGroup = array();
|
||||
$localAssetsExtraGroup = array();
|
||||
|
||||
$docLocationElements = $domTag->getElementsByTagName($docLocationTag)->item(0);
|
||||
|
||||
if ($docLocationElements === null) { continue; }
|
||||
|
||||
$xpath = new \DOMXpath($domTag);
|
||||
$linkTags = $xpath->query('/html/'.$docLocationTag.'/link[@rel="stylesheet"] | /html/'.$docLocationTag.'/link[@rel="preload"]');
|
||||
if ($linkTags === null) { continue; }
|
||||
|
||||
foreach ($linkTags as $tagObject) {
|
||||
$linkAttributes = array();
|
||||
foreach ($tagObject->attributes as $attrObj) { $linkAttributes[$attrObj->nodeName] = trim($attrObj->nodeValue); }
|
||||
|
||||
// Only rel="stylesheet" (with no rel="preload" associated with it) gets prepared for combining as links with rel="preload" (if any) are never combined into a standard render-blocking CSS file
|
||||
// rel="preload" is there for a reason to make sure the CSS code is made available earlier prior to the one from rel="stylesheet" which is render-blocking
|
||||
if (isset($linkAttributes['rel'], $linkAttributes['href']) && $linkAttributes['href']) {
|
||||
$href = (string) $linkAttributes['href'];
|
||||
|
||||
if (self::skipCombine($linkAttributes['href'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// e.g. for 'admin-bar' (keep it as standalone when critical CSS is used)
|
||||
if (isset($linkAttributes['data-wpacu-skip-preload']) && has_filter('wpacu_critical_css')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the CSS file has any 'data-wpacu-skip' attribute; if it does, do not alter it
|
||||
if (isset($linkAttributes['data-wpacu-skip']) || isset($scriptAttributes['data-wpacu-apply-media-query'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Separate each combined group by the "media" attribute; e.g. we don't want "all" and "print" mixed
|
||||
$mediaValue = (array_key_exists('media', $linkAttributes) && $linkAttributes['media']) ? $linkAttributes['media'] : 'all';
|
||||
|
||||
// Check if there is any rel="preload" (Basic) connected to the rel="stylesheet"
|
||||
// making sure the file is not added to the final CSS combined file
|
||||
if (isset($linkAttributes['data-wpacu-style-handle']) &&
|
||||
$linkAttributes['data-wpacu-style-handle'] &&
|
||||
ObjectCache::wpacu_cache_get($linkAttributes['data-wpacu-style-handle'], 'wpacu_basic_preload_handles')) {
|
||||
$mediaValue = 'wpacu_preload_basic_' . $mediaValue;
|
||||
}
|
||||
|
||||
// Make the right reference for later use
|
||||
if ($linkAttributes['rel'] === 'preload') {
|
||||
if (isset($linkAttributes['data-wpacu-preload-css-basic'])) {
|
||||
$mediaValue = 'wpacu_preload_basic_' . $mediaValue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Was it optimized and has the URL updated? Check the Source URL to determine if it should be skipped from combining
|
||||
if (isset($linkAttributes['data-wpacu-link-rel-href-before']) && $linkAttributes['data-wpacu-link-rel-href-before'] && self::skipCombine($linkAttributes['data-wpacu-link-rel-href-before'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid combining own plugin's CSS (irrelevant) as it takes extra useless space in the caching directory
|
||||
if (isset($linkAttributes['id']) && $linkAttributes['id'] === WPACU_PLUGIN_ID.'-style-css') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localAssetPath = OptimizeCommon::getLocalAssetPath($href, 'css');
|
||||
|
||||
// It will skip external stylesheets (from a different domain)
|
||||
if ( $localAssetPath ) {
|
||||
$styleExtra = array();
|
||||
|
||||
if (isset($linkAttributes['data-wpacu-style-handle'], $wpacuRegisteredStyles[$linkAttributes['data-wpacu-style-handle']]->extra) && OptimizeCommon::appendInlineCodeToCombineAssetType('css')) {
|
||||
$styleExtra = $wpacuRegisteredStyles[$linkAttributes['data-wpacu-style-handle']]->extra;
|
||||
}
|
||||
|
||||
$sourceRelPath = OptimizeCommon::getSourceRelPath($href);
|
||||
|
||||
$alreadyAddedSourceRelPath = isset($combinedUriPathsGroup[$mediaValue]) && in_array($sourceRelPath, $combinedUriPathsGroup[$mediaValue]);
|
||||
if (! $alreadyAddedSourceRelPath) {
|
||||
$combinedUriPathsGroup[$mediaValue][] = $sourceRelPath;
|
||||
}
|
||||
|
||||
$localAssetsPathsGroup[$mediaValue][$href] = $localAssetPath;
|
||||
|
||||
$alreadyAddedHref = isset($linkHrefsGroup[$mediaValue]) && in_array($href, $linkHrefsGroup[$mediaValue]);
|
||||
if (! $alreadyAddedHref) {
|
||||
$linkHrefsGroup[$mediaValue][] = $href;
|
||||
}
|
||||
|
||||
$localAssetsExtraGroup[$mediaValue][$href] = $styleExtra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No Link Tags or only one tag in the combined group? Do not proceed with any combining
|
||||
if ( empty( $combinedUriPathsGroup ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($combinedUriPathsGroup as $mediaValue => $combinedUriPaths) {
|
||||
// There have to be at least two CSS files to create a combined CSS file
|
||||
if (count($combinedUriPaths) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localAssetsPaths = $localAssetsPathsGroup[$mediaValue];
|
||||
$linkHrefs = $linkHrefsGroup[$mediaValue];
|
||||
$localAssetsExtra = array_filter($localAssetsExtraGroup[$mediaValue]);
|
||||
|
||||
$maybeDoCssCombine = self::maybeDoCssCombine(
|
||||
$localAssetsPaths,
|
||||
$linkHrefs,
|
||||
$localAssetsExtra,
|
||||
$docLocationTag
|
||||
);
|
||||
|
||||
// Local path to combined CSS file
|
||||
$localFinalCssFile = $maybeDoCssCombine['local_final_css_file'];
|
||||
|
||||
// URI (e.g. /wp-content/cache/asset-cleanup/[file-name-here.css]) to the combined CSS file
|
||||
$uriToFinalCssFile = $maybeDoCssCombine['uri_final_css_file'];
|
||||
|
||||
// Any link hrefs removed perhaps if the file wasn't combined?
|
||||
$linkHrefs = $maybeDoCssCombine['link_hrefs'];
|
||||
|
||||
if (is_file($localFinalCssFile)) {
|
||||
$storageJsonContents[$docLocationTag][$mediaValue] = array(
|
||||
'uri_to_final_css_file' => $uriToFinalCssFile,
|
||||
'link_hrefs' => array_map(static function($href) {
|
||||
return str_replace('{site_url}', '', OptimizeCommon::getSourceRelPath($href));
|
||||
}, $linkHrefs)
|
||||
);
|
||||
|
||||
$storageJsonContentsToSave[$docLocationTag][$mediaValue] = array(
|
||||
'uri_to_final_css_file' => $uriToFinalCssFile,
|
||||
'link_hrefs' => array_map(static function($href) {
|
||||
return OptimizeCommon::getSourceRelPath($href);
|
||||
}, $linkHrefs)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
|
||||
OptimizeCommon::setAssetCachedData(
|
||||
self::$jsonStorageFile,
|
||||
OptimizeCss::getRelPathCssCacheDir(),
|
||||
wp_json_encode($storageJsonContentsToSave)
|
||||
);
|
||||
}
|
||||
|
||||
$cdnUrls = OptimizeCommon::getAnyCdnUrls();
|
||||
$cdnUrlForCss = isset($cdnUrls['css']) ? $cdnUrls['css'] : false;
|
||||
|
||||
if ( ! empty($storageJsonContents) ) {
|
||||
foreach ($storageJsonContents as $docLocationTag => $mediaValues) {
|
||||
$groupLocation = 1;
|
||||
|
||||
foreach ($mediaValues as $mediaValue => $storageJsonContentLocation) {
|
||||
if (! isset($storageJsonContentLocation['link_hrefs'][0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Irrelevant to have only one CSS file in a combine CSS group
|
||||
if (count($storageJsonContentLocation['link_hrefs']) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storageJsonContentLocation['link_hrefs'] = array_map(static function($href) {
|
||||
return str_replace('{site_url}', '', $href);
|
||||
}, $storageJsonContentLocation['link_hrefs']);
|
||||
|
||||
$finalTagUrl = OptimizeCommon::filterWpContentUrl($cdnUrlForCss) . OptimizeCss::getRelPathCssCacheDir() . $storageJsonContentLocation['uri_to_final_css_file'];
|
||||
|
||||
$finalCssTagAttrs = array();
|
||||
|
||||
if (strpos($mediaValue, 'wpacu_preload_basic_') === 0) {
|
||||
// Put the right "media" value after cleaning the reference
|
||||
$mediaValueClean = str_replace('wpacu_preload_basic_', '', $mediaValue);
|
||||
|
||||
// Basic Preload
|
||||
$finalCssTag = <<<HTML
|
||||
<link rel='stylesheet' data-wpacu-to-be-preloaded-basic='1' id='wpacu-combined-css-{$docLocationTag}-{$groupLocation}-preload-it-basic' href='{$finalTagUrl}' type='text/css' media='{$mediaValueClean}' />
|
||||
HTML;
|
||||
$finalCssTagRelPreload = <<<HTML
|
||||
<link rel='preload' as='style' data-wpacu-preload-it-basic='1' id='wpacu-combined-css-{$docLocationTag}-{$groupLocation}-preload-it-basic' href='{$finalTagUrl}' type='text/css' media='{$mediaValueClean}' />
|
||||
HTML;
|
||||
|
||||
$finalCssTagAttrs['rel'] = 'preload';
|
||||
$finalCssTagAttrs['media'] = $mediaValueClean;
|
||||
|
||||
$htmlSource = str_replace(Preloads::DEL_STYLES_PRELOADS, $finalCssTagRelPreload."\n" . Preloads::DEL_STYLES_PRELOADS, $htmlSource);
|
||||
} else {
|
||||
// Render-blocking CSS
|
||||
$finalCssTag = <<<HTML
|
||||
<link rel='stylesheet' id='wpacu-combined-css-{$docLocationTag}-{$groupLocation}' href='{$finalTagUrl}' type='text/css' media='{$mediaValue}' />
|
||||
HTML;
|
||||
$finalCssTagAttrs['rel'] = 'stylesheet';
|
||||
$finalCssTagAttrs['media'] = $mediaValue;
|
||||
}
|
||||
|
||||
// In case one (e.g. usually a developer) needs to alter it
|
||||
$finalCssTag = apply_filters(
|
||||
'wpacu_combined_css_tag',
|
||||
$finalCssTag,
|
||||
array(
|
||||
'attrs' => $finalCssTagAttrs,
|
||||
'doc_location' => $docLocationTag,
|
||||
'group_no' => $groupLocation,
|
||||
'href' => $finalTagUrl
|
||||
)
|
||||
);
|
||||
|
||||
// Reference: https://stackoverflow.com/questions/2368539/php-replacing-multiple-spaces-with-a-single-space
|
||||
$finalCssTag = preg_replace('!\s+!', ' ', $finalCssTag);
|
||||
|
||||
$htmlSourceBeforeAnyLinkTagReplacement = $htmlSource;
|
||||
|
||||
// Detect first LINK tag from the <$locationTag> and replace it with the final combined LINK tag
|
||||
$firstLinkTag = OptimizeCss::getFirstLinkTag($storageJsonContentLocation['link_hrefs'][0], $htmlSource);
|
||||
|
||||
if ($firstLinkTag) {
|
||||
// 1) Strip inline code before/after it (if any)
|
||||
// 2) Finally, strip the actual tag
|
||||
$htmlSource = self::stripTagAndAnyInlineAssocCode( $firstLinkTag, $wpacuRegisteredStyles, $finalCssTag, $htmlSource );
|
||||
}
|
||||
|
||||
if ($htmlSource !== $htmlSourceBeforeAnyLinkTagReplacement) {
|
||||
$htmlSource = self::stripJustCombinedLinkTags(
|
||||
$storageJsonContentLocation['link_hrefs'],
|
||||
$wpacuRegisteredStyles,
|
||||
$htmlSource
|
||||
); // Strip the combined files to avoid duplicate code
|
||||
|
||||
// There should be at least two replacements made AND all the tags should have been replaced
|
||||
// Leave no room for errors, otherwise the page could end up with extra files loaded, leading to a slower website
|
||||
if ($htmlSource === 'do_not_combine') {
|
||||
$htmlSource = $htmlSourceBeforeAnyLinkTagReplacement;
|
||||
} else {
|
||||
$groupLocation++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filesSources
|
||||
* @param $wpacuRegisteredStyles
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function stripJustCombinedLinkTags($filesSources, $wpacuRegisteredStyles, $htmlSource)
|
||||
{
|
||||
preg_match_all('#<link[^>]*(stylesheet|preload)[^>]*(>)#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
|
||||
|
||||
$linkTagsStrippedNo = 0;
|
||||
|
||||
foreach ($matchesSourcesFromTags as $matchSourceFromTag) {
|
||||
$matchedSourceFromTag = (isset($matchSourceFromTag[0]) && strip_tags($matchSourceFromTag[0]) === '') ? trim($matchSourceFromTag[0]) : '';
|
||||
|
||||
if (! $matchSourceFromTag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The DOMDocument is already checked if it's enabled in doCombine()
|
||||
$domTag = Misc::initDOMDocument();
|
||||
$domTag->loadHTML($matchedSourceFromTag);
|
||||
|
||||
foreach ($domTag->getElementsByTagName('link') as $tagObject) {
|
||||
if (empty($tagObject->attributes)) { continue; }
|
||||
|
||||
foreach ($tagObject->attributes as $tagAttrs) {
|
||||
if ($tagAttrs->nodeName === 'href') {
|
||||
$relNodeValue = trim(OptimizeCommon::getSourceRelPath($tagAttrs->nodeValue));
|
||||
|
||||
if (in_array($relNodeValue, $filesSources)) {
|
||||
$htmlSourceBeforeLinkTagReplacement = $htmlSource;
|
||||
|
||||
// 1) Strip inline code before/after it (if any)
|
||||
// 2) Finally, strip the actual tag
|
||||
$htmlSource = self::stripTagAndAnyInlineAssocCode( $matchedSourceFromTag, $wpacuRegisteredStyles, '', $htmlSource );
|
||||
|
||||
if ($htmlSource !== $htmlSourceBeforeLinkTagReplacement) {
|
||||
$linkTagsStrippedNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
}
|
||||
|
||||
// Aren't all the LINK tags stripped? They should be, otherwise, do not proceed with the HTML alteration (no combining will take place)
|
||||
// Minus the already combined tag
|
||||
if (($linkTagsStrippedNo < 2) && (count($filesSources) !== $linkTagsStrippedNo)) {
|
||||
return 'do_not_combine';
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $href
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function skipCombine($href)
|
||||
{
|
||||
$regExps = array(
|
||||
'#/wp-content/bs-booster-cache/#'
|
||||
);
|
||||
|
||||
if (Main::instance()->settings['combine_loaded_css_exceptions'] !== '') {
|
||||
$loadedCssExceptionsPatterns = trim(Main::instance()->settings['combine_loaded_css_exceptions']);
|
||||
|
||||
if (strpos($loadedCssExceptionsPatterns, "\n")) {
|
||||
// Multiple values (one per line)
|
||||
foreach (explode("\n", $loadedCssExceptionsPatterns) as $loadedCssExceptionPattern) {
|
||||
$regExps[] = '#'.trim($loadedCssExceptionPattern).'#';
|
||||
}
|
||||
} else {
|
||||
// Only one value?
|
||||
$regExps[] = '#'.trim($loadedCssExceptionsPatterns).'#';
|
||||
}
|
||||
}
|
||||
|
||||
// No exceptions set? Do not skip combination
|
||||
if (empty($regExps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($regExps as $regExp) {
|
||||
$regExp = Misc::purifyRegexValue($regExp);
|
||||
|
||||
if ( @preg_match( $regExp, $href ) || ( strpos($href, $regExp) !== false ) ) {
|
||||
// Skip combination
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localAssetsPaths
|
||||
* @param $linkHrefs
|
||||
* @param $localAssetsExtra
|
||||
* @param $docLocationTag
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function maybeDoCssCombine($localAssetsPaths, $linkHrefs, $localAssetsExtra, $docLocationTag)
|
||||
{
|
||||
// Only combine if $shaOneCombinedUriPaths.css does not exist
|
||||
// If "?ver" value changes on any of the assets or the asset list changes in any way
|
||||
// then $shaOneCombinedUriPaths will change too and a new CSS file will be generated and loaded
|
||||
|
||||
// Change $finalCombinedCssContent as paths to fonts and images that are relative (e.g. ../, ../../) have to be updated + other optimization changes
|
||||
$uriToFinalCssFile = $localFinalCssFile = $finalCombinedCssContent = '';
|
||||
|
||||
foreach ($localAssetsPaths as $assetHref => $localAssetsPath) {
|
||||
if ($cssContent = trim(FileSystem::fileGetContents($localAssetsPath, 'combine_css_imports'))) {
|
||||
$pathToAssetDir = OptimizeCommon::getPathToAssetDir($assetHref);
|
||||
|
||||
// Does it have a source map? Strip it
|
||||
if (strpos($cssContent, '/*# sourceMappingURL=') !== false) {
|
||||
$cssContent = OptimizeCommon::stripSourceMap($cssContent, 'css');
|
||||
}
|
||||
|
||||
if (apply_filters('wpacu_print_info_comments_in_cached_assets', true)) {
|
||||
$finalCombinedCssContent .= '/*!' . str_replace( Misc::getWpRootDirPath(), '/', $localAssetsPath ) . "*/\n";
|
||||
}
|
||||
|
||||
$finalCombinedCssContent .= OptimizeCss::maybeFixCssContent($cssContent, $pathToAssetDir . '/') . "\n";
|
||||
|
||||
$finalCombinedCssContent = self::appendToCombineCss($localAssetsExtra, $assetHref, $pathToAssetDir, $finalCombinedCssContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
|
||||
$finalCombinedCssContent = trim(OptimizeCss::importsUpdate($finalCombinedCssContent));
|
||||
|
||||
if (Main::instance()->settings['google_fonts_remove']) {
|
||||
$finalCombinedCssContent = FontsGoogleRemove::cleanFontFaceReferences($finalCombinedCssContent);
|
||||
}
|
||||
|
||||
$finalCombinedCssContent = apply_filters('wpacu_local_fonts_display_css_output', $finalCombinedCssContent, Main::instance()->settings['local_fonts_display']);
|
||||
|
||||
if ($finalCombinedCssContent) {
|
||||
$finalCombinedCssContent = trim($finalCombinedCssContent);
|
||||
$shaOneForCombinedCss = sha1($finalCombinedCssContent);
|
||||
|
||||
$uriToFinalCssFile = $docLocationTag . '-' .$shaOneForCombinedCss . '.css';
|
||||
$localFinalCssFile = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir() . $uriToFinalCssFile;
|
||||
|
||||
if (! is_file($localFinalCssFile)) {
|
||||
FileSystem::filePutContents($localFinalCssFile, $finalCombinedCssContent);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'uri_final_css_file' => $uriToFinalCssFile,
|
||||
'local_final_css_file' => $localFinalCssFile,
|
||||
'link_hrefs' => $linkHrefs
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localAssetsExtra
|
||||
* @param $assetHref
|
||||
* @param $pathToAssetDir
|
||||
* @param $finalAssetsContents
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function appendToCombineCss($localAssetsExtra, $assetHref, $pathToAssetDir, $finalAssetsContents)
|
||||
{
|
||||
if (isset($localAssetsExtra[$assetHref]['after']) && ! empty($localAssetsExtra[$assetHref]['after'])) {
|
||||
$afterCssContent = '';
|
||||
|
||||
foreach ($localAssetsExtra[$assetHref]['after'] as $afterData) {
|
||||
if (! is_bool($afterData)) {
|
||||
$afterCssContent .= $afterData."\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($afterCssContent)) {
|
||||
if (MinifyCss::isMinifyCssEnabled() && in_array(Main::instance()->settings['minify_loaded_css_for'], array('inline', 'all'))) {
|
||||
$afterCssContent = MinifyCss::applyMinification( $afterCssContent );
|
||||
}
|
||||
|
||||
$afterCssContent = OptimizeCss::maybeFixCssContent( $afterCssContent, $pathToAssetDir . '/' );
|
||||
|
||||
$finalAssetsContents .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [inline: after] */' : '';
|
||||
$finalAssetsContents .= $afterCssContent;
|
||||
$finalAssetsContents .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [/inline: after] */' : '';
|
||||
$finalAssetsContents .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $finalAssetsContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* The targeted LINK tag (which was enqueued and has a handle) is replaced with $replaceWith
|
||||
* along with any inline content that was added after it via wp_add_inline_style()
|
||||
*
|
||||
* @param $targetedLinkTag
|
||||
* @param $wpacuRegisteredStyles
|
||||
* @param $replaceWith
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function stripTagAndAnyInlineAssocCode($targetedLinkTag, $wpacuRegisteredStyles, $replaceWith, $htmlSource)
|
||||
{
|
||||
if (OptimizeCommon::appendInlineCodeToCombineAssetType('css')) {
|
||||
$scriptExtrasHtml = OptimizeCss::getInlineAssociatedWithLinkHandle($targetedLinkTag, $wpacuRegisteredStyles, 'tag', 'html');
|
||||
$scriptExtraAfterHtml = (isset($scriptExtrasHtml['after']) && $scriptExtrasHtml['after']) ? "\n".$scriptExtrasHtml['after'] : '';
|
||||
|
||||
$htmlSource = str_replace(
|
||||
array(
|
||||
$targetedLinkTag . $scriptExtraAfterHtml,
|
||||
$targetedLinkTag . trim($scriptExtraAfterHtml)
|
||||
),
|
||||
$replaceWith,
|
||||
$htmlSource
|
||||
);
|
||||
}
|
||||
|
||||
return str_replace(
|
||||
array(
|
||||
$targetedLinkTag."\n",
|
||||
$targetedLinkTag
|
||||
),
|
||||
$replaceWith."\n",
|
||||
$htmlSource
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function proceedWithCssCombine()
|
||||
{
|
||||
// Not on query string request (debugging purposes)
|
||||
if ( ! empty($_REQUEST) && array_key_exists('wpacu_no_css_combine', $_REQUEST) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No CSS files are combined in the Dashboard
|
||||
// Always in the front-end view
|
||||
// Do not combine if there's a POST request as there could be assets loading conditionally
|
||||
// that might not be needed when the page is accessed without POST, making the final CSS file larger
|
||||
if (! empty($_POST) || is_admin()) {
|
||||
return false; // Do not combine
|
||||
}
|
||||
|
||||
// Only clean request URIs allowed (with Exceptions)
|
||||
// Exceptions
|
||||
if ((strpos($_SERVER['REQUEST_URI'], '?') !== false) && ! OptimizeCommon::loadOptimizedAssetsIfQueryStrings()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! OptimizeCommon::doCombineIsRegularPage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pluginSettings = Main::instance()->settings;
|
||||
|
||||
if ($pluginSettings['test_mode'] && ! Menu::userCanManageAssets()) {
|
||||
return false; // Do not combine anything if "Test Mode" is ON and the user is in guest mode (not logged-in)
|
||||
}
|
||||
|
||||
if ($pluginSettings['combine_loaded_css'] === '') {
|
||||
return false; // Do not combine
|
||||
}
|
||||
|
||||
if (OptimizeCss::isOptimizeCssEnabledByOtherParty('if_enabled')) {
|
||||
return false; // Do not combine (it's already enabled in other plugin)
|
||||
}
|
||||
|
||||
// "Minify HTML" from WP Rocket is sometimes stripping combined LINK tags
|
||||
// Better uncombined then missing essential CSS files
|
||||
if (Misc::isWpRocketMinifyHtmlEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// The option is no longer used since v1.1.7.3 (Pro) & v1.3.6.4 (Lite)
|
||||
if ( ($pluginSettings['combine_loaded_css'] === 'for_admin'
|
||||
|| $pluginSettings['combine_loaded_css_for_admin_only'] == 1)
|
||||
&& Menu::userCanManageAssets()) {
|
||||
|
||||
return true; // Do combine
|
||||
}
|
||||
*/
|
||||
|
||||
// "Apply it only for guest visitors (default)" is set; Do not combine if the user is logged in
|
||||
if ( $pluginSettings['combine_loaded_css_for'] === 'guests' && is_user_logged_in() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($pluginSettings['combine_loaded_css'], array('for_all', 1)) ) {
|
||||
return true; // Do combine
|
||||
}
|
||||
|
||||
// Finally, return false as none of the verification above matched
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,514 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use MatthiasMullie\Minify\Minify;
|
||||
|
||||
use MatthiasMullie\PathConverter\ConverterInterface;
|
||||
use MatthiasMullie\PathConverter\Converter;
|
||||
|
||||
/**
|
||||
* Combine CSS Imports extended from CSS minifier
|
||||
*
|
||||
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
||||
*
|
||||
* @package Minify
|
||||
* @author Matthias Mullie <minify@mullie.eu>
|
||||
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
||||
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
||||
* @license MIT License
|
||||
*/
|
||||
class CombineCssImports extends Minify
|
||||
{
|
||||
/**
|
||||
* @var int maximum import size in kB
|
||||
*/
|
||||
protected $maxImportSize = 5;
|
||||
|
||||
/**
|
||||
* @var string[] valid import extensions
|
||||
*/
|
||||
protected $importExtensions = array(
|
||||
'gif' => 'data:image/gif',
|
||||
'png' => 'data:image/png',
|
||||
'jpe' => 'data:image/jpeg',
|
||||
'jpg' => 'data:image/jpeg',
|
||||
'jpeg' => 'data:image/jpeg',
|
||||
'svg' => 'data:image/svg+xml',
|
||||
'woff' => 'data:application/x-font-woff',
|
||||
'tif' => 'image/tiff',
|
||||
'tiff' => 'image/tiff',
|
||||
'xbm' => 'image/x-xbitmap',
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the maximum size if files to be imported.
|
||||
*
|
||||
* Files larger than this size (in kB) will not be imported into the CSS.
|
||||
* Importing files into the CSS as data-uri will save you some connections,
|
||||
* but we should only import relatively small decorative images so that our
|
||||
* CSS file doesn't get too bulky.
|
||||
*
|
||||
* @param int $size Size in kB
|
||||
*/
|
||||
public function setMaxImportSize($size)
|
||||
{
|
||||
$this->maxImportSize = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of extensions to be imported into the CSS (to save network
|
||||
* connections).
|
||||
* Keys of the array should be the file extensions & respective values
|
||||
* should be the data type.
|
||||
*
|
||||
* @param string[] $extensions Array of file extensions
|
||||
*/
|
||||
public function setImportExtensions(array $extensions)
|
||||
{
|
||||
$this->importExtensions = $extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move any import statements to the top.
|
||||
*
|
||||
* @param string $content Nearly finished CSS content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function moveImportsToTop($content)
|
||||
{
|
||||
if (preg_match_all('/(;?)(@import (?<url>url\()?(?P<quotes>["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
|
||||
// remove from content
|
||||
foreach ($matches[0] as $import) {
|
||||
$content = str_replace($import, '', $content);
|
||||
}
|
||||
|
||||
// add to top
|
||||
$content = implode(';', $matches[2]).';'.trim($content, ';');
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine CSS from import statements.
|
||||
*
|
||||
* @import's will be loaded and their content merged into the original file,
|
||||
* to save HTTP requests.
|
||||
*
|
||||
* @param string $source The file to combine imports for
|
||||
* @param string $content The CSS content to combine imports for
|
||||
* @param string[] $parents Parent paths, for circular reference checks
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function combineImports($source, $content, $parents)
|
||||
{
|
||||
$importRegexes = array(
|
||||
// @import url(xxx)
|
||||
'/
|
||||
# import statement
|
||||
@import
|
||||
|
||||
# whitespace
|
||||
\s+
|
||||
|
||||
# open url()
|
||||
url\(
|
||||
|
||||
# (optional) open path enclosure
|
||||
(?P<quotes>["\']?)
|
||||
|
||||
# fetch path
|
||||
(?P<path>.+?)
|
||||
|
||||
# (optional) close path enclosure
|
||||
(?P=quotes)
|
||||
|
||||
# close url()
|
||||
\)
|
||||
|
||||
# (optional) trailing whitespace
|
||||
\s*
|
||||
|
||||
# (optional) media statement(s)
|
||||
(?P<media>[^;]*)
|
||||
|
||||
# (optional) trailing whitespace
|
||||
\s*
|
||||
|
||||
# (optional) closing semi-colon
|
||||
;?
|
||||
|
||||
/ix',
|
||||
|
||||
// @import 'xxx'
|
||||
'/
|
||||
|
||||
# import statement
|
||||
@import
|
||||
|
||||
# whitespace
|
||||
\s+
|
||||
|
||||
# open path enclosure
|
||||
(?P<quotes>["\'])
|
||||
|
||||
# fetch path
|
||||
(?P<path>.+?)
|
||||
|
||||
# close path enclosure
|
||||
(?P=quotes)
|
||||
|
||||
# (optional) trailing whitespace
|
||||
\s*
|
||||
|
||||
# (optional) media statement(s)
|
||||
(?P<media>[^;]*)
|
||||
|
||||
# (optional) trailing whitespace
|
||||
\s*
|
||||
|
||||
# (optional) closing semi-colon
|
||||
;?
|
||||
|
||||
/ix',
|
||||
);
|
||||
|
||||
// find all relative imports in css
|
||||
$matches = array();
|
||||
foreach ($importRegexes as $importRegex) {
|
||||
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
||||
$matches = array_merge($matches, $regexMatches);
|
||||
}
|
||||
}
|
||||
|
||||
$search = array();
|
||||
$replace = array();
|
||||
|
||||
// loop the matches
|
||||
foreach ($matches as $match) {
|
||||
// get the path for the file that will be imported
|
||||
$importPath = dirname($source).'/'.$match['path'];
|
||||
|
||||
// only replace the import with the content if we can grab the
|
||||
// content of the file
|
||||
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if current file was not imported previously in the same
|
||||
// import chain.
|
||||
if (in_array($importPath, $parents)) {
|
||||
// No need to have and endless loop (the same file imported again and again)
|
||||
$search[] = $match[0];
|
||||
$replace[] = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
// grab referenced file & optimize it (which may include importing
|
||||
// yet other @import statements recursively)
|
||||
$minifier = new static($importPath);
|
||||
$minifier->setMaxImportSize($this->maxImportSize);
|
||||
$minifier->setImportExtensions($this->importExtensions);
|
||||
$importContent = $minifier->execute($source, $parents);
|
||||
|
||||
// check if this is only valid for certain media
|
||||
if (!empty($match['media'])) {
|
||||
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
|
||||
}
|
||||
|
||||
// add to replacement array
|
||||
$search[] = $match[0];
|
||||
$replace[] = $importContent;
|
||||
}
|
||||
|
||||
// replace the import statements
|
||||
return str_replace($search, $replace, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $css
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function alterImportsBetweenComments($css)
|
||||
{
|
||||
// RegEx Source: https://blog.ostermiller.org/finding-comments-in-source-code-using-regular-expressions/
|
||||
preg_match_all('#/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/#', $css, $commentsMatches);
|
||||
|
||||
if (isset($commentsMatches[0]) && ! empty($commentsMatches[0])) {
|
||||
foreach ($commentsMatches[0] as $commentMatch) {
|
||||
if (strpos($commentMatch, '@import') === false) {
|
||||
continue; // the comment needs to have @import
|
||||
}
|
||||
|
||||
$newComment = str_replace('@import', '(wpacu)(at)import', $commentMatch);
|
||||
$css = str_replace($commentMatch, $newComment, $css);
|
||||
}
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import files into the CSS, base64-sized.
|
||||
*
|
||||
* @url(image.jpg) images will be loaded and their content merged into the
|
||||
* original file, to save HTTP requests.
|
||||
*
|
||||
* @param string $source The file to import files for
|
||||
* @param string $content The CSS content to import files for
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function importFiles($source, $content)
|
||||
{
|
||||
$regex = '/url\((["\']?)(.+?)\\1\)/i';
|
||||
if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
|
||||
$search = array();
|
||||
$replace = array();
|
||||
|
||||
// loop the matches
|
||||
foreach ($matches as $match) {
|
||||
$extension = substr(strrchr($match[2], '.'), 1);
|
||||
if ($extension && !array_key_exists($extension, $this->importExtensions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the path for the file that will be imported
|
||||
$path = $match[2];
|
||||
$path = dirname($source).'/'.$path;
|
||||
|
||||
// only replace the import with the content if we're able to get
|
||||
// the content of the file, and it's relatively small
|
||||
if ($this->canImportFile($path) && $this->canImportBySize($path)) {
|
||||
// grab content && base64-ize
|
||||
$importContent = $this->load($path);
|
||||
$importContent = base64_encode($importContent);
|
||||
|
||||
// build replacement
|
||||
$search[] = $match[0];
|
||||
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
|
||||
}
|
||||
}
|
||||
|
||||
// replace the import statements
|
||||
$content = str_replace($search, $replace, $content);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform CSS optimizations.
|
||||
*
|
||||
* @param string[optional] $path Path to write the data to
|
||||
* @param string[] $parents Parent paths, for circular reference checks
|
||||
*
|
||||
* @return string The minified data
|
||||
*/
|
||||
public function execute($path = null, $parents = array())
|
||||
{
|
||||
$content = '';
|
||||
|
||||
// loop CSS data (raw data and files)
|
||||
foreach ($this->data as $source => $css) {
|
||||
// Some developers might have wrapped @import between comments
|
||||
// No import for those
|
||||
$css = $this->alterImportsBetweenComments($css);
|
||||
|
||||
$source = is_int($source) ? '' : $source;
|
||||
$parents = $source ? array_merge($parents, array($source)) : $parents;
|
||||
$css = $this->combineImports($source, $css, $parents);
|
||||
$css = $this->importFiles($source, $css);
|
||||
|
||||
/*
|
||||
* If we'll save to a new path, we'll have to fix the relative paths
|
||||
* to be relative no longer to the source file, but to the new path.
|
||||
* If we don't write to a file, fall back to same path so no
|
||||
* conversion happens (because we still want it to go through most
|
||||
* of the move code, which also addresses url() & @import syntax...)
|
||||
*/
|
||||
$converter = $this->getPathConverter($source, $path ?: $source);
|
||||
$css = $this->move($converter, $css);
|
||||
|
||||
// combine css
|
||||
$content .= $css;
|
||||
}
|
||||
|
||||
$content = $this->moveImportsToTop($content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moving a css file should update all relative urls.
|
||||
* Relative references (e.g. ../images/image.gif) in a certain css file,
|
||||
* will have to be updated when a file is being saved at another location
|
||||
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
|
||||
*
|
||||
* @param ConverterInterface $converter Relative path converter
|
||||
* @param string $content The CSS content to update relative urls for
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function move(ConverterInterface $converter, $content)
|
||||
{
|
||||
/*
|
||||
* Relative path references will usually be enclosed by url(). @import
|
||||
* is an exception, where url() is not necessary around the path (but is
|
||||
* allowed).
|
||||
* This *could* be 1 regular expression, where both regular expressions
|
||||
* in this array are on different sides of a |. But we're using named
|
||||
* patterns in both regexes, the same name on both regexes. This is only
|
||||
* possible with a (?J) modifier, but that only works after a fairly
|
||||
* recent PCRE version. That's why I'm doing 2 separate regular
|
||||
* expressions & combining the matches after executing of both.
|
||||
*/
|
||||
$relativeRegexes = array(
|
||||
// url(xxx)
|
||||
'/
|
||||
# open url()
|
||||
url\(
|
||||
|
||||
\s*
|
||||
|
||||
# open path enclosure
|
||||
(?P<quotes>["\'])?
|
||||
|
||||
# fetch path
|
||||
(?P<path>.+?)
|
||||
|
||||
# close path enclosure
|
||||
(?(quotes)(?P=quotes))
|
||||
|
||||
\s*
|
||||
|
||||
# close url()
|
||||
\)
|
||||
|
||||
/ix',
|
||||
|
||||
// @import "xxx"
|
||||
'/
|
||||
# import statement
|
||||
@import
|
||||
|
||||
# whitespace
|
||||
\s+
|
||||
|
||||
# we don\'t have to check for @import url(), because the
|
||||
# condition above will already catch these
|
||||
|
||||
# open path enclosure
|
||||
(?P<quotes>["\'])
|
||||
|
||||
# fetch path
|
||||
(?P<path>.+?)
|
||||
|
||||
# close path enclosure
|
||||
(?P=quotes)
|
||||
|
||||
/ix',
|
||||
);
|
||||
|
||||
// find all relative urls in css
|
||||
$matches = array();
|
||||
foreach ($relativeRegexes as $relativeRegex) {
|
||||
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
||||
$matches = array_merge($matches, $regexMatches);
|
||||
}
|
||||
}
|
||||
|
||||
$search = array();
|
||||
$replace = array();
|
||||
|
||||
// loop all urls
|
||||
foreach ($matches as $match) {
|
||||
// determine if it's an url() or an @import match
|
||||
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
|
||||
|
||||
$url = $match['path'];
|
||||
if ($this->canImportByPath($url)) {
|
||||
// attempting to interpret GET-params makes no sense, so let's discard them for a while
|
||||
$params = strrchr($url, '?');
|
||||
$url = $params ? substr($url, 0, -strlen($params)) : $url;
|
||||
|
||||
// fix relative url
|
||||
$url = $converter->convert($url);
|
||||
|
||||
// now that the path has been converted, re-apply GET-params
|
||||
$url .= $params;
|
||||
}
|
||||
|
||||
/*
|
||||
* Urls with control characters above 0x7e should be quoted.
|
||||
* According to Mozilla's parser, whitespace is only allowed at the
|
||||
* end of unquoted urls.
|
||||
* Urls with `)` (as could happen with data: uris) should also be
|
||||
* quoted to avoid being confused for the url() closing parentheses.
|
||||
* And urls with a # have also been reported to cause issues.
|
||||
* Urls with quotes inside should also remain escaped.
|
||||
*
|
||||
* @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
|
||||
* @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
|
||||
* @see https://github.com/matthiasmullie/minify/issues/193
|
||||
*/
|
||||
$url = trim($url);
|
||||
if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) {
|
||||
$url = $match['quotes'] . $url . $match['quotes'];
|
||||
}
|
||||
|
||||
// build replacement
|
||||
$search[] = $match[0];
|
||||
if ($type === 'url') {
|
||||
$replace[] = 'url('.$url.')';
|
||||
} elseif ($type === 'import') {
|
||||
$replace[] = '@import "'.$url.'"';
|
||||
}
|
||||
}
|
||||
|
||||
// replace urls
|
||||
return str_replace($search, $replace, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file is small enough to be imported.
|
||||
*
|
||||
* @param string $path The path to the file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function canImportBySize($path)
|
||||
{
|
||||
return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file a file can be imported, going by the path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function canImportByPath($path)
|
||||
{
|
||||
return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a converter to update relative paths to be relative to the new
|
||||
* destination.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
*
|
||||
* @return ConverterInterface
|
||||
*/
|
||||
protected function getPathConverter($source, $target)
|
||||
{
|
||||
return new Converter($source, $target);
|
||||
}
|
||||
}
|
@ -0,0 +1,920 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Menu;
|
||||
use WpAssetCleanUp\FileSystem;
|
||||
use WpAssetCleanUp\Misc;
|
||||
use WpAssetCleanUp\ObjectCache;
|
||||
|
||||
/**
|
||||
* Class CombineJs
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class CombineJs
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $jsonStorageFile = 'js-combined{maybe-extra-info}.json';
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function doCombine($htmlSource)
|
||||
{
|
||||
if ( ! Misc::isDOMDocumentOn() ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
if ( ! self::proceedWithJsCombine() ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
global $wp_scripts;
|
||||
$wpacuRegisteredScripts = $wp_scripts->registered;
|
||||
|
||||
$combineLevel = 2;
|
||||
|
||||
$isDeferAppliedOnBodyCombineGroupNo = false;
|
||||
|
||||
// $uriToFinalJsFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathJsCacheDir()
|
||||
// which is usually "wp-content/cache/asset-cleanup/js/"
|
||||
|
||||
// "true" would make it avoid checking the cache and always use the DOM Parser / RegExp
|
||||
// for DEV purposes ONLY as it uses more resources
|
||||
$finalCacheList = array();
|
||||
$skipCache = false;
|
||||
|
||||
if (isset($_GET['wpacu_no_cache']) || (defined('WPACU_NO_CACHE') && WPACU_NO_CACHE === true)) {
|
||||
$skipCache = true;
|
||||
}
|
||||
|
||||
if (! $skipCache) {
|
||||
// Speed up processing by getting the already existing final CSS file URI
|
||||
// This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
|
||||
$finalCacheList = OptimizeCommon::getAssetCachedData( self::$jsonStorageFile, OptimizeJs::getRelPathJsCacheDir(), 'js' );
|
||||
}
|
||||
|
||||
if ( $skipCache || empty($finalCacheList) ) {
|
||||
/*
|
||||
* NO CACHING TRANSIENT; Parse the DOM
|
||||
*/
|
||||
// Nothing in the database records or the retrieved cached file does not exist?
|
||||
OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
|
||||
|
||||
$combinableList = array();
|
||||
|
||||
$jQueryMigrateInBody = false;
|
||||
$jQueryLibInBodyCount = 0;
|
||||
|
||||
$minifyJsInlineTagsIsNotEnabled = ! (MinifyJs::isMinifyJsEnabled() && in_array(Main::instance()->settings['minify_loaded_js_for'], array('inline', 'all')));
|
||||
|
||||
if ($minifyJsInlineTagsIsNotEnabled) {
|
||||
$domTag = Misc::initDOMDocument();
|
||||
|
||||
// Strip irrelevant tags to boost the speed of the parser (e.g. NOSCRIPT / SCRIPT(inline) / STYLE)
|
||||
// Sometimes, inline CODE can be too large, and it takes extra time for loadHTML() to parse
|
||||
$htmlSourceAlt = preg_replace( '@<script(| (type=(\'|"|)text/(javascript|template|html)(\'|"|)))>.*?</script>@si', '', $htmlSource );
|
||||
$htmlSourceAlt = preg_replace( '@<(style|noscript)[^>]*?>.*?</\\1>@si', '', $htmlSourceAlt );
|
||||
$htmlSourceAlt = preg_replace( '#<link([^<>]+)/?>#iU', '', $htmlSourceAlt );
|
||||
|
||||
if (Main::instance()->isFrontendEditView) {
|
||||
$htmlSourceAlt = preg_replace( '@<form action="#wpacu_wrap_assets" method="post">.*?</form>@si', '', $htmlSourceAlt );
|
||||
}
|
||||
|
||||
if ($htmlSourceAlt === '') {
|
||||
$htmlSourceAlt = $htmlSource;
|
||||
}
|
||||
|
||||
$domTag->loadHTML( $htmlSourceAlt );
|
||||
} else {
|
||||
$domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'combineJs');
|
||||
}
|
||||
|
||||
// Only keep combinable JS files
|
||||
foreach ( array( 'head', 'body' ) as $docLocationScript ) {
|
||||
$groupIndex = 1;
|
||||
|
||||
$docLocationElements = $domTag->getElementsByTagName($docLocationScript)->item(0);
|
||||
if ($docLocationElements === null) { continue; }
|
||||
|
||||
// High accuracy (e.g. it ignores tags inside HTML comments, conditional or not)
|
||||
$scriptTags = $docLocationElements->getElementsByTagName('script');
|
||||
if ($scriptTags === null) { continue; }
|
||||
|
||||
if ($docLocationScript && Main::instance()->settings['combine_loaded_js_defer_body']) {
|
||||
ObjectCache::wpacu_cache_set('wpacu_html_dom_body_tag_for_js', $docLocationElements);
|
||||
}
|
||||
|
||||
foreach ($scriptTags as $tagObject) {
|
||||
$scriptAttributes = array();
|
||||
|
||||
if ( isset($tagObject->attributes) && ! empty($tagObject->attributes) ) {
|
||||
foreach ( $tagObject->attributes as $attrObj ) {
|
||||
$scriptAttributes[ $attrObj->nodeName ] = trim( $attrObj->nodeValue );
|
||||
}
|
||||
}
|
||||
|
||||
$scriptNotCombinable = false; // default (usually, most of the SCRIPT tags can be optimized)
|
||||
|
||||
// Check if the CSS file has any 'data-wpacu-skip' attribute; if it does, do not alter it
|
||||
if (isset($scriptAttributes['data-wpacu-skip'])) {
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
|
||||
$handleToCheck = isset($scriptAttributes['data-wpacu-script-handle']) ? $scriptAttributes['data-wpacu-script-handle'] : ''; // Maybe: JS Inline (Before, After)
|
||||
$hasSrc = isset($scriptAttributes['src']) && trim($scriptAttributes['src']); // No valid SRC attribute? It's not combinable (e.g. an inline tag)
|
||||
$isPluginScript = isset($scriptAttributes['data-wpacu-plugin-script']); // Only of the user is logged-in (skip it as it belongs to the Asset CleanUp (Pro) plugin)
|
||||
|
||||
if (! $scriptNotCombinable && (! $hasSrc || $isPluginScript)) {
|
||||
// Inline tag? Skip it in the BODY
|
||||
if ($docLocationScript === 'body') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Because of jQuery, we will not have the list of all inline scripts and then the combined files as it is in BODY
|
||||
if ($docLocationScript === 'head') {
|
||||
if ($handleToCheck === '' && isset($scriptAttributes['id'])) {
|
||||
$replaceToGetHandle = '';
|
||||
if (strpos($scriptAttributes['id'], '-js-extra') !== false) { $replaceToGetHandle = '-js-extra'; }
|
||||
if (strpos($scriptAttributes['id'], '-js-before') !== false) { $replaceToGetHandle = '-js-before'; }
|
||||
if (strpos($scriptAttributes['id'], '-js-after') !== false) { $replaceToGetHandle = '-js-after'; }
|
||||
if (strpos($scriptAttributes['id'], '-js-translations') !== false) { $replaceToGetHandle = '-js-translations'; }
|
||||
|
||||
if ($replaceToGetHandle) {
|
||||
$handleToCheck = str_replace( $replaceToGetHandle, '', $scriptAttributes['id'] ); // Maybe: JS Inline (Data)
|
||||
}
|
||||
}
|
||||
|
||||
// Once an inline SCRIPT (with few exceptions below), except the ones associated with an enqueued script tag (with "src") is stumbled upon, a new combined group in the HEAD tag will be formed
|
||||
if ($handleToCheck && OptimizeCommon::appendInlineCodeToCombineAssetType('js')) {
|
||||
$getInlineAssociatedWithHandle = OptimizeJs::getInlineAssociatedWithScriptHandle($handleToCheck, $wpacuRegisteredScripts, 'handle');
|
||||
|
||||
if ( ($getInlineAssociatedWithHandle['data'] || $getInlineAssociatedWithHandle['before'] || $getInlineAssociatedWithHandle['after'])
|
||||
|| in_array(trim($tagObject->nodeValue), array($getInlineAssociatedWithHandle['data'], $getInlineAssociatedWithHandle['before'], $getInlineAssociatedWithHandle['after']))
|
||||
|| (strpos(trim($tagObject->nodeValue), '/* <![CDATA[ */') === 0 && Misc::endsWith(trim($tagObject->nodeValue), '/* ]]> */')) ) {
|
||||
|
||||
// It's associated with the enqueued scripts, or it's a (standalone) CDATA inline tag added via wp_localize_script()
|
||||
// Skip it instead and if the CDATA is not standalone (e.g. not associated with any script tag), the loop will "stay" in the same combined group
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
}
|
||||
|
||||
$isInGroupType = 'standard';
|
||||
$isJQueryLib = $isJQueryMigrate = false;
|
||||
|
||||
// Has SRC and $isPluginScript is set to false OR it does not have "data-wpacu-skip" attribute
|
||||
if (! $scriptNotCombinable) {
|
||||
$src = (string)$scriptAttributes['src'];
|
||||
|
||||
if (self::skipCombine($src, $handleToCheck)) {
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
|
||||
// Avoid any errors when code like the following one is used:
|
||||
// wp.i18n.setLocaleData( localeData, domain );
|
||||
// Because the inline JS is not appended to the combined JS, /wp-includes/js/dist/i18n.(min).js has to be called earlier (outside the combined JS file)
|
||||
if ( ! OptimizeCommon::appendInlineCodeToCombineAssetType('js') && (strpos($src, '/wp-includes/js/dist/i18n.') !== false) ) {
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
|
||||
if (isset($scriptAttributes['data-wpacu-to-be-preloaded-basic']) && $scriptAttributes['data-wpacu-to-be-preloaded-basic']) {
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
|
||||
// Was it optimized and has the URL updated? Check the Source URL
|
||||
if (! $scriptNotCombinable && isset($scriptAttributes['data-wpacu-script-rel-src-before']) && $scriptAttributes['data-wpacu-script-rel-src-before'] && self::skipCombine($scriptAttributes['data-wpacu-script-rel-src-before'], $handleToCheck)) {
|
||||
$scriptNotCombinable = true;
|
||||
}
|
||||
|
||||
$isJQueryLib = isset($scriptAttributes['data-wpacu-jquery-core-handle']);
|
||||
$isJQueryMigrate = isset($scriptAttributes['data-wpacu-jquery-migrate-handle']);
|
||||
|
||||
if (isset($scriptAttributes['async'], $scriptAttributes['defer'])) { // Has both "async" and "defer"
|
||||
$isInGroupType = 'async_defer';
|
||||
} elseif (isset($scriptAttributes['async'])) { // Has only "async"
|
||||
$isInGroupType = 'async';
|
||||
} elseif (isset($scriptAttributes['defer'])) { // Has only "defer"
|
||||
// Does it have "defer" attribute, it's combinable (all checks were already done), loads in the BODY tag and "combine_loaded_js_defer_body" is ON? Keep it to the combination list
|
||||
$isCombinableWithBodyDefer = (! $scriptNotCombinable && $docLocationScript === 'body' && Main::instance()->settings['combine_loaded_js_defer_body']);
|
||||
|
||||
if (! $isCombinableWithBodyDefer) {
|
||||
$isInGroupType = 'defer'; // Otherwise, add it to the "defer" group type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $scriptNotCombinable ) {
|
||||
// It also checks the domain name to make sure no external scripts would be added to the list
|
||||
if ( $localAssetPath = OptimizeCommon::getLocalAssetPath( $src, 'js' ) ) {
|
||||
$scriptExtra = array();
|
||||
|
||||
if ( isset( $scriptAttributes['data-wpacu-script-handle'], $wpacuRegisteredScripts[ $scriptAttributes['data-wpacu-script-handle'] ]->extra ) && OptimizeCommon::appendInlineCodeToCombineAssetType('js') ) {
|
||||
$scriptExtra = $wpacuRegisteredScripts[ $scriptAttributes['data-wpacu-script-handle'] ]->extra;
|
||||
|
||||
$anyScriptTranslations = method_exists('wp_scripts', 'print_translations')
|
||||
? wp_scripts()->print_translations( $scriptAttributes['data-wpacu-script-handle'], false )
|
||||
: false;
|
||||
|
||||
if ( $anyScriptTranslations ) {
|
||||
$scriptExtra['translations'] = $anyScriptTranslations;
|
||||
}
|
||||
}
|
||||
|
||||
// Standard (could be multiple groups per $docLocationScript), Async & Defer, Async, Defer
|
||||
$groupByType = ($isInGroupType === 'standard') ? $groupIndex : $isInGroupType;
|
||||
|
||||
if ($docLocationScript === 'body') {
|
||||
if ($isJQueryLib || strpos($localAssetPath, '/wp-includes/js/jquery/jquery.js') !== false) {
|
||||
$jQueryLibInBodyCount++;
|
||||
}
|
||||
|
||||
if ($isJQueryMigrate || strpos($localAssetPath, '/wp-includes/js/jquery/jquery-migrate') !== false) {
|
||||
$jQueryLibInBodyCount++;
|
||||
$jQueryMigrateInBody = true;
|
||||
}
|
||||
}
|
||||
|
||||
$combinableList[$docLocationScript][$groupByType][] = array(
|
||||
'src' => $src,
|
||||
'local' => $localAssetPath,
|
||||
'info' => array(
|
||||
'is_jquery' => $isJQueryLib,
|
||||
'is_jquery_migrate' => $isJQueryMigrate
|
||||
),
|
||||
'extra' => $scriptExtra
|
||||
);
|
||||
|
||||
if ($docLocationScript === 'body' && $jQueryLibInBodyCount === 2) {
|
||||
$jQueryLibInBodyCount = 0; // reset it
|
||||
$groupIndex ++; // a new JS group will be created if jQuery & jQuery Migrate are combined in the BODY
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$groupIndex ++; // a new JS group will be created (applies to "standard" ones only)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could be pages such as maintenance mode with no external JavaScript files
|
||||
if (empty($combinableList)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$finalCacheList = array();
|
||||
|
||||
foreach ($combinableList as $docLocationScript => $combinableListGroups) {
|
||||
$groupNo = 1;
|
||||
|
||||
foreach ($combinableListGroups as $groupType => $groupFiles) {
|
||||
// Any groups having one file? Then it's not really a group and the file should load on its own
|
||||
// Could be one extra file besides the jQuery & jQuery Migrate group or the only JS file called within the HEAD
|
||||
if (count($groupFiles) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localAssetsPaths = $groupScriptSrcs = array();
|
||||
$localAssetsExtra = array();
|
||||
$jQueryIsIncludedInGroup = false;
|
||||
|
||||
foreach ($groupFiles as $groupFileData) {
|
||||
if ($groupFileData['info']['is_jquery'] || strpos($groupFileData['local'], '/wp-includes/js/jquery/jquery.js') !== false) {
|
||||
$jQueryIsIncludedInGroup = true;
|
||||
|
||||
// Is jQuery in the BODY without jQuery Migrate loaded?
|
||||
// Isolate it as it needs to be the first to load in case there are inline scripts calling it before the combined group(s)
|
||||
if ($docLocationScript === 'body' && ! $jQueryMigrateInBody) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$src = $groupFileData['src'];
|
||||
$groupScriptSrcs[] = $src;
|
||||
$localAssetsPaths[$src] = $groupFileData['local'];
|
||||
$localAssetsExtra[$src] = $groupFileData['extra'];
|
||||
}
|
||||
|
||||
$maybeDoJsCombine = self::maybeDoJsCombine(
|
||||
$localAssetsPaths,
|
||||
$localAssetsExtra,
|
||||
$docLocationScript
|
||||
);
|
||||
|
||||
// Local path to combined CSS file
|
||||
$localFinalJsFile = $maybeDoJsCombine['local_final_js_file'];
|
||||
|
||||
// URI (e.g. /wp-content/cache/asset-cleanup/[file-name-here.js]) to the combined JS file
|
||||
$uriToFinalJsFile = $maybeDoJsCombine['uri_final_js_file'];
|
||||
|
||||
if (! is_file($localFinalJsFile)) {
|
||||
return $htmlSource; // something is not right as the file wasn't created, we will return the original HTML source
|
||||
}
|
||||
|
||||
$groupScriptSrcsFilter = array_map(static function($src) {
|
||||
$src = str_replace(site_url(), '', $src);
|
||||
// Starts with // (protocol is missing) - the replacement above wasn't made
|
||||
if (strpos($src, '//') === 0) {
|
||||
$siteUrlNoProtocol = str_replace(array('http:', 'https:'), '', site_url());
|
||||
return str_replace($siteUrlNoProtocol, '', $src);
|
||||
}
|
||||
return $src;
|
||||
}, $groupScriptSrcs);
|
||||
|
||||
$finalCacheList[$docLocationScript][$groupNo] = array(
|
||||
'uri_to_final_js_file' => $uriToFinalJsFile,
|
||||
'script_srcs' => $groupScriptSrcsFilter
|
||||
);
|
||||
|
||||
if (in_array($groupType, array('async_defer', 'async', 'defer'))) {
|
||||
if ($groupType === 'async_defer') {
|
||||
$finalCacheList[$docLocationScript][$groupNo]['extra_attributes'][] = 'async';
|
||||
$finalCacheList[$docLocationScript][$groupNo]['extra_attributes'][] = 'defer';
|
||||
} else {
|
||||
$finalCacheList[$docLocationScript][$groupNo]['extra_attributes'][] = $groupType;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply 'defer="defer"' to combined JS files from the BODY tag (if enabled), except the combined jQuery & jQuery Migrate Group
|
||||
if ($docLocationScript === 'body' && ! $jQueryIsIncludedInGroup && Main::instance()->settings['combine_loaded_js_defer_body']) {
|
||||
if ($isDeferAppliedOnBodyCombineGroupNo === false) {
|
||||
// Only record the first one
|
||||
$isDeferAppliedOnBodyCombineGroupNo = $groupNo;
|
||||
}
|
||||
|
||||
$finalCacheList[$docLocationScript][$groupNo]['extra_attributes'][] = 'defer';
|
||||
}
|
||||
|
||||
$groupNo ++;
|
||||
}
|
||||
}
|
||||
|
||||
OptimizeCommon::setAssetCachedData(self::$jsonStorageFile, OptimizeJs::getRelPathJsCacheDir(), wp_json_encode($finalCacheList));
|
||||
}
|
||||
|
||||
if (! empty($finalCacheList)) {
|
||||
$cdnUrls = OptimizeCommon::getAnyCdnUrls();
|
||||
$cdnUrlForJs = isset($cdnUrls['js']) ? $cdnUrls['js'] : false;
|
||||
|
||||
foreach ( $finalCacheList as $docLocationScript => $cachedGroupsList ) {
|
||||
foreach ($cachedGroupsList as $groupNo => $cachedValues) {
|
||||
$htmlSourceBeforeGroupReplacement = $htmlSource;
|
||||
|
||||
$uriToFinalJsFile = $cachedValues['uri_to_final_js_file'];
|
||||
$filesSources = $cachedValues['script_srcs'];
|
||||
|
||||
// Basic Combining (1) -> replace "first" tag with the final combination tag (there would be most likely multiple groups)
|
||||
// Enhanced Combining (2) -> replace "last" tag with the final combination tag (most likely one group)
|
||||
$indexReplacement = ($combineLevel === 2) ? (count($filesSources) - 1) : 0;
|
||||
|
||||
$finalTagUrl = OptimizeCommon::filterWpContentUrl($cdnUrlForJs) . OptimizeJs::getRelPathJsCacheDir() . $uriToFinalJsFile;
|
||||
|
||||
$finalJsTagAttrsOutput = '';
|
||||
$extraAttrs = array();
|
||||
|
||||
if (isset($cachedValues['extra_attributes']) && ! empty($cachedValues['extra_attributes'])) {
|
||||
$extraAttrs = $cachedValues['extra_attributes'];
|
||||
foreach ($extraAttrs as $finalJsTagAttr) {
|
||||
$finalJsTagAttrsOutput .= ' '.$finalJsTagAttr.'=\''.$finalJsTagAttr.'\' ';
|
||||
}
|
||||
$finalJsTagAttrsOutput = trim($finalJsTagAttrsOutput);
|
||||
}
|
||||
|
||||
// No async or defer? Add the preloading for the combined JS from the BODY
|
||||
if ( ! $finalJsTagAttrsOutput && $docLocationScript === 'body' ) {
|
||||
$finalJsTagAttrsOutput = ' data-wpacu-to-be-preloaded-basic=\'1\' ';
|
||||
if ( ! defined('WPACU_REAPPLY_PRELOADING_FOR_COMBINED_JS') ) { define('WPACU_REAPPLY_PRELOADING_FOR_COMBINED_JS', true); }
|
||||
}
|
||||
|
||||
// e.g. For developers that might want to add custom attributes such as data-cfasync="false"
|
||||
$finalJsTag = apply_filters(
|
||||
'wpacu_combined_js_tag',
|
||||
'<script '.$finalJsTagAttrsOutput.' '.Misc::getScriptTypeAttribute().' id=\'wpacu-combined-js-'.$docLocationScript.'-group-'.$groupNo.'\' src=\''.$finalTagUrl.'\'></script>',
|
||||
array(
|
||||
'attrs' => $extraAttrs,
|
||||
'doc_location' => $docLocationScript,
|
||||
'group_no' => $groupNo,
|
||||
'src' => $finalTagUrl
|
||||
)
|
||||
);
|
||||
|
||||
// Reference: https://stackoverflow.com/questions/2368539/php-replacing-multiple-spaces-with-a-single-space
|
||||
$finalJsTag = preg_replace('!\s+!', ' ', $finalJsTag);
|
||||
|
||||
$scriptTagsStrippedNo = 0;
|
||||
|
||||
$scriptTags = OptimizeJs::getScriptTagsFromSrcs($filesSources, $htmlSource);
|
||||
|
||||
foreach ($scriptTags as $groupScriptTagIndex => $scriptTag) {
|
||||
$replaceWith = ($groupScriptTagIndex === $indexReplacement) ? $finalJsTag : '';
|
||||
$htmlSourceBeforeTagReplacement = $htmlSource;
|
||||
|
||||
// 1) Strip any inline code associated with the tag
|
||||
// 2) Finally, strip the actual tag
|
||||
$htmlSource = self::stripTagAndAnyInlineAssocCode( $scriptTag, $wpacuRegisteredScripts, $replaceWith, $htmlSource );
|
||||
|
||||
if ($htmlSource !== $htmlSourceBeforeTagReplacement) {
|
||||
$scriptTagsStrippedNo ++;
|
||||
}
|
||||
}
|
||||
|
||||
// At least two tags have to be stripped from the group to consider doing the group replacement
|
||||
// If the tags weren't replaced it's likely there were changes to their structure after they were cached for the group merging
|
||||
if (count($filesSources) !== $scriptTagsStrippedNo) {
|
||||
$htmlSource = $htmlSourceBeforeGroupReplacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only relevant if "Defer loading JavaScript combined files from <body>" in "Settings" - "Combine CSS & JS Files" - "Combine loaded JS (JavaScript) into fewer files"
|
||||
// and there is at least one combined deferred tag
|
||||
|
||||
if (isset($finalCacheList['body']) && (! empty($finalCacheList['body'])) && Main::instance()->settings['combine_loaded_js_defer_body']) {
|
||||
// CACHE RE-BUILT
|
||||
if ($isDeferAppliedOnBodyCombineGroupNo > 0 && $domTag = ObjectCache::wpacu_cache_get('wpacu_html_dom_body_tag_for_js')) {
|
||||
$strPart = "id='wpacu-combined-js-body-group-".$isDeferAppliedOnBodyCombineGroupNo."' ";
|
||||
|
||||
if (strpos($htmlSource, $strPart) === false) {
|
||||
return $htmlSource; // something is funny, do not continue
|
||||
}
|
||||
|
||||
list(,$htmlAfterFirstCombinedDeferScript) = explode($strPart, $htmlSource);
|
||||
$htmlAfterFirstCombinedDeferScriptMaybeChanged = $htmlAfterFirstCombinedDeferScript;
|
||||
$scriptTags = $domTag->getElementsByTagName('script');
|
||||
} else {
|
||||
// FROM THE CACHE
|
||||
foreach ($finalCacheList['body'] as $bodyCombineGroupNo => $values) {
|
||||
if (isset($values['extra_attributes']) && in_array('defer', $values['extra_attributes'])) {
|
||||
$isDeferAppliedOnBodyCombineGroupNo = $bodyCombineGroupNo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $isDeferAppliedOnBodyCombineGroupNo) {
|
||||
// Not applicable to any combined group
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$strPart = 'id=\'wpacu-combined-js-body-group-'.$isDeferAppliedOnBodyCombineGroupNo.'\'';
|
||||
|
||||
$htmlAfterFirstCombinedDeferScriptMaybeChanged = false;
|
||||
|
||||
if (strpos($htmlSource, $strPart) !== false) {
|
||||
list( , $htmlAfterFirstCombinedDeferScript ) = explode( $strPart, $htmlSource );
|
||||
$htmlAfterFirstCombinedDeferScriptMaybeChanged = $htmlAfterFirstCombinedDeferScript;
|
||||
}
|
||||
|
||||
// It means to combine took place for any reason (e.g. only one JS file loaded in the HEAD and one in the BODY)
|
||||
if (! isset($htmlAfterFirstCombinedDeferScript)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$domTag = Misc::initDOMDocument();
|
||||
|
||||
// Strip irrelevant tags to boost the speed of the parser (e.g. NOSCRIPT / SCRIPT(inline) / STYLE)
|
||||
// Sometimes, inline CODE can be too large, and it takes extra time for loadHTML() to parse
|
||||
$htmlSourceAlt = preg_replace( '@<script(| type=\'text/javascript\'| type="text/javascript")>.*?</script>@si', '', $htmlAfterFirstCombinedDeferScript );
|
||||
$htmlSourceAlt = preg_replace( '@<(style|noscript)[^>]*?>.*?</\\1>@si', '', $htmlSourceAlt );
|
||||
$htmlSourceAlt = preg_replace( '#<link([^<>]+)/?>#iU', '', $htmlSourceAlt );
|
||||
|
||||
if (Main::instance()->isFrontendEditView) {
|
||||
$htmlSourceAlt = preg_replace( '@<form action="#wpacu_wrap_assets" method="post">.*?</form>@si', '', $htmlSourceAlt );
|
||||
}
|
||||
|
||||
// No other SCRIPT left, stop here in this case
|
||||
if (strpos($htmlSourceAlt, '<script') === false) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$domTag->loadHTML( $htmlSourceAlt );
|
||||
$scriptTags = $domTag->getElementsByTagName('script');
|
||||
}
|
||||
|
||||
if ( $scriptTags === null ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($scriptTags as $tagObject) {
|
||||
if (empty($tagObject->attributes)) { continue; }
|
||||
|
||||
$scriptAttributes = array();
|
||||
|
||||
foreach ( $tagObject->attributes as $attrObj ) {
|
||||
$scriptAttributes[ $attrObj->nodeName ] = trim( $attrObj->nodeValue );
|
||||
}
|
||||
|
||||
// No "src" attribute? Skip it (most likely an inline script tag)
|
||||
if (! (isset($scriptAttributes['src']) && $scriptAttributes['src'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip it as "defer" is already set
|
||||
if (isset($scriptAttributes['defer'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Has "src" attribute and "defer" is not applied? Add it
|
||||
if ($htmlAfterFirstCombinedDeferScriptMaybeChanged !== false) {
|
||||
$htmlAfterFirstCombinedDeferScriptMaybeChanged = trim( preg_replace(
|
||||
'#\ssrc(\s+|)=(\s+|)(|"|\'|\s+)(' . preg_quote( $scriptAttributes['src'], '/' ) . ')(\3)#si',
|
||||
' src=\3\4\3 defer=\'defer\'',
|
||||
$htmlAfterFirstCombinedDeferScriptMaybeChanged
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
if ($htmlAfterFirstCombinedDeferScriptMaybeChanged && $htmlAfterFirstCombinedDeferScriptMaybeChanged !== $htmlAfterFirstCombinedDeferScript) {
|
||||
$htmlSource = str_replace($htmlAfterFirstCombinedDeferScript, $htmlAfterFirstCombinedDeferScriptMaybeChanged, $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
|
||||
// Finally, return the HTML source
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $src
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function skipCombine($src, $handle = '')
|
||||
{
|
||||
// In case the handle was appended
|
||||
if ($handle !== '' && in_array($handle, Main::instance()->skipAssets['scripts'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$regExps = array(
|
||||
'#/wp-content/bs-booster-cache/#'
|
||||
);
|
||||
|
||||
if (Main::instance()->settings['combine_loaded_js_exceptions'] !== '') {
|
||||
$loadedJsExceptionsPatterns = trim(Main::instance()->settings['combine_loaded_js_exceptions']);
|
||||
|
||||
if (strpos($loadedJsExceptionsPatterns, "\n")) {
|
||||
// Multiple values (one per line)
|
||||
foreach (explode("\n", $loadedJsExceptionsPatterns) as $loadedJsExceptionsPattern) {
|
||||
$regExps[] = '#'.trim($loadedJsExceptionsPattern).'#';
|
||||
}
|
||||
} else {
|
||||
// Only one value?
|
||||
$regExps[] = '#'.trim($loadedJsExceptionsPatterns).'#';
|
||||
}
|
||||
}
|
||||
|
||||
// No exceptions set? Do not skip combination
|
||||
if (empty($regExps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($regExps as $regExp) {
|
||||
$regExp = Misc::purifyRegexValue($regExp);
|
||||
|
||||
if ( @preg_match( $regExp, $src ) || ( strpos($src, $regExp) !== false ) ) {
|
||||
// Skip combination
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localAssetsPaths
|
||||
* @param $localAssetsExtra
|
||||
* @param $docLocationScript
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function maybeDoJsCombine($localAssetsPaths, $localAssetsExtra, $docLocationScript)
|
||||
{
|
||||
// Only combine if $shaOneCombinedUriPaths.js does not exist
|
||||
// If "?ver" value changes on any of the assets or the asset list changes in any way
|
||||
// then $shaOneCombinedUriPaths will change too and a new JS file will be generated and loaded
|
||||
|
||||
// Change $assetsContents as paths to fonts and images that are relative (e.g. ../, ../../) have to be updated
|
||||
$uriToFinalJsFile = $localFinalJsFile = $finalJsContents = '';
|
||||
|
||||
foreach ($localAssetsPaths as $assetHref => $localAssetsPath) {
|
||||
if ($jsContent = trim(FileSystem::fileGetContents($localAssetsPath))) {
|
||||
// Does it have a source map? Strip it
|
||||
if (strpos($jsContent, '//# sourceMappingURL=') !== false) {
|
||||
$jsContent = OptimizeCommon::stripSourceMap($jsContent, 'js');
|
||||
}
|
||||
|
||||
$pathToAssetDir = OptimizeCommon::getPathToAssetDir($assetHref);
|
||||
|
||||
$contentToAddToCombinedFile = '';
|
||||
|
||||
if (apply_filters('wpacu_print_info_comments_in_cached_assets', true)) {
|
||||
$contentToAddToCombinedFile = '/*!' . str_replace( Misc::getWpRootDirPath(), '/', $localAssetsPath ) . "*/\n";
|
||||
}
|
||||
|
||||
// This includes the extra from 'data' (CDATA added via wp_localize_script()) & 'before' as they are both printed BEFORE the SCRIPT tag
|
||||
$contentToAddToCombinedFile .= self::maybeWrapBetweenTryCatch(self::appendToCombineJs('translations', $localAssetsExtra, $assetHref, $pathToAssetDir), $assetHref);
|
||||
$contentToAddToCombinedFile .= self::maybeWrapBetweenTryCatch(self::appendToCombineJs('before', $localAssetsExtra, $assetHref, $pathToAssetDir), $assetHref);
|
||||
$contentToAddToCombinedFile .= self::maybeWrapBetweenTryCatch(OptimizeJs::maybeDoJsFixes($jsContent, $pathToAssetDir . '/'), $assetHref) . "\n";
|
||||
// This includes the inline 'after' the SCRIPT tag
|
||||
$contentToAddToCombinedFile .= self::maybeWrapBetweenTryCatch(self::appendToCombineJs('after', $localAssetsExtra, $assetHref, $pathToAssetDir), $assetHref);
|
||||
|
||||
$finalJsContents .= $contentToAddToCombinedFile;
|
||||
}
|
||||
}
|
||||
|
||||
if ($finalJsContents !== '') {
|
||||
$finalJsContents = trim($finalJsContents);
|
||||
$shaOneForCombinedJs = sha1($finalJsContents);
|
||||
|
||||
$uriToFinalJsFile = $docLocationScript . '-' . $shaOneForCombinedJs . '.js';
|
||||
$localFinalJsFile = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir() . $uriToFinalJsFile;
|
||||
|
||||
if (! is_file($localFinalJsFile)) {
|
||||
FileSystem::filePutContents( $localFinalJsFile, $finalJsContents );
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'uri_final_js_file' => $uriToFinalJsFile,
|
||||
'local_final_js_file' => $localFinalJsFile
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $addItLocation
|
||||
* @param $localAssetsExtra
|
||||
* @param $assetHref
|
||||
* @param $pathToAssetDir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function appendToCombineJs($addItLocation, $localAssetsExtra, $assetHref, $pathToAssetDir)
|
||||
{
|
||||
$extraContentToAppend = '';
|
||||
$doJsMinifyInline = MinifyJs::isMinifyJsEnabled() && in_array(Main::instance()->settings['minify_loaded_js_for'], array('inline', 'all'));
|
||||
|
||||
if ($addItLocation === 'before') {
|
||||
// [Before JS Content]
|
||||
if (isset($localAssetsExtra[$assetHref]['data']) && ($dataValue = $localAssetsExtra[$assetHref]['data'])) {
|
||||
$extraContentToAppend = '';
|
||||
if (self::isInlineJsCombineable($dataValue) && trim($dataValue) !== '') {
|
||||
$cData = $doJsMinifyInline ? MinifyJs::applyMinification( $dataValue ) : $dataValue;
|
||||
$cData = OptimizeJs::maybeDoJsFixes( $cData, $pathToAssetDir . '/' );
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [inline: cdata] */' : '';
|
||||
$extraContentToAppend .= $cData;
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [/inline: cdata] */' : '';
|
||||
$extraContentToAppend .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($localAssetsExtra[$assetHref]['before']) && ! empty($localAssetsExtra[$assetHref]['before'])) {
|
||||
$inlineBeforeJsData = '';
|
||||
|
||||
foreach ($localAssetsExtra[$assetHref]['before'] as $beforeData) {
|
||||
if (! is_bool($beforeData) && self::isInlineJsCombineable($beforeData)) {
|
||||
$inlineBeforeJsData .= $beforeData . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($inlineBeforeJsData)) {
|
||||
$inlineBeforeJsData = OptimizeJs::maybeAlterContentForInlineScriptTag( $inlineBeforeJsData, $doJsMinifyInline );
|
||||
$inlineBeforeJsData = OptimizeJs::maybeDoJsFixes( $inlineBeforeJsData, $pathToAssetDir . '/' );
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [inline: before] */' : '';
|
||||
$extraContentToAppend .= $inlineBeforeJsData;
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [/inline: before] */' : '';
|
||||
$extraContentToAppend .= "\n";
|
||||
}
|
||||
}
|
||||
// [/Before JS Content]
|
||||
} elseif ($addItLocation === 'after') {
|
||||
// [After JS Content]
|
||||
if (isset($localAssetsExtra[$assetHref]['after']) && ! empty($localAssetsExtra[$assetHref]['after'])) {
|
||||
$inlineAfterJsData = '';
|
||||
|
||||
foreach ($localAssetsExtra[$assetHref]['after'] as $afterData) {
|
||||
if (! is_bool($afterData) && self::isInlineJsCombineable($afterData)) {
|
||||
$inlineAfterJsData .= $afterData."\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( trim($inlineAfterJsData) ) {
|
||||
$inlineAfterJsData = OptimizeJs::maybeAlterContentForInlineScriptTag( $inlineAfterJsData, $doJsMinifyInline );
|
||||
$inlineAfterJsData = OptimizeJs::maybeDoJsFixes( $inlineAfterJsData, $pathToAssetDir . '/' );
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [inline: after] */' : '';
|
||||
$extraContentToAppend .= $inlineAfterJsData;
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [/inline: after] */' : '';
|
||||
$extraContentToAppend .= "\n";
|
||||
}
|
||||
}
|
||||
// [/After JS Content]
|
||||
} elseif ($addItLocation === 'translations' && isset($localAssetsExtra[$assetHref]['translations']) && $localAssetsExtra[$assetHref]['translations']) {
|
||||
$inlineAfterJsData = OptimizeJs::maybeAlterContentForInlineScriptTag( $localAssetsExtra[$assetHref]['translations'], $doJsMinifyInline );
|
||||
$inlineAfterJsData = OptimizeJs::maybeDoJsFixes( $inlineAfterJsData, $pathToAssetDir . '/' );
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [inline: translations] */' : '';
|
||||
$extraContentToAppend .= $inlineAfterJsData;
|
||||
$extraContentToAppend .= apply_filters('wpacu_print_info_comments_in_cached_assets', true) ? '/* [/inline: translations] */' : '';
|
||||
$extraContentToAppend .= "\n";
|
||||
}
|
||||
|
||||
return $extraContentToAppend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $jsCode
|
||||
* @param $sourceUrl
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function maybeWrapBetweenTryCatch($jsCode, $sourceUrl)
|
||||
{
|
||||
if ($jsCode && Main::instance()->settings['combine_loaded_js_try_catch']) {
|
||||
return <<<JS
|
||||
try {
|
||||
{$jsCode}
|
||||
} catch (err) {
|
||||
console.log("Asset CleanUp - There is a JavaScript error related to the following source: {$sourceUrl} - Error: " + err.message);
|
||||
}
|
||||
JS;
|
||||
}
|
||||
|
||||
return $jsCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $scriptTag
|
||||
* @param $wpacuRegisteredScripts
|
||||
* @param $replaceWith
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function stripTagAndAnyInlineAssocCode($scriptTag, $wpacuRegisteredScripts, $replaceWith, $htmlSource)
|
||||
{
|
||||
if (OptimizeCommon::appendInlineCodeToCombineAssetType('js')) {
|
||||
$scriptExtrasValue = OptimizeJs::getInlineAssociatedWithScriptHandle($scriptTag, $wpacuRegisteredScripts, 'tag', 'value');
|
||||
|
||||
$scriptExtraTranslationsValue = (isset($scriptExtrasValue['translations']) && $scriptExtrasValue['translations']) ? $scriptExtrasValue['translations'] : '';
|
||||
$scriptExtraCdataValue = (isset($scriptExtrasValue['data']) && $scriptExtrasValue['data']) ? $scriptExtrasValue['data'] : '';
|
||||
$scriptExtraBeforeValue = (isset($scriptExtrasValue['before']) && $scriptExtrasValue['before']) ? $scriptExtrasValue['before'] : '';
|
||||
$scriptExtraAfterValue = (isset($scriptExtrasValue['after']) && $scriptExtrasValue['after']) ? $scriptExtrasValue['after'] : '';
|
||||
|
||||
$scriptExtrasHtml = OptimizeJs::getInlineAssociatedWithScriptHandle($scriptTag, $wpacuRegisteredScripts, 'tag', 'html');
|
||||
preg_match_all('#data-wpacu-script-handle=([\'])' . '(.*)' . '(\1)#Usmi', $scriptTag, $outputMatches);
|
||||
$scriptHandle = (isset($outputMatches[2][0]) && $outputMatches[2][0]) ? trim($outputMatches[2][0], '"\'') : '';
|
||||
|
||||
$scriptExtraTranslationsHtml = (isset($scriptExtrasHtml['translations']) && $scriptExtrasHtml['translations']) ? $scriptExtrasHtml['translations'] : '';
|
||||
$scriptExtraCdataHtml = (isset($scriptExtrasHtml['data']) && $scriptExtrasHtml['data']) ? $scriptExtrasHtml['data'] : '';
|
||||
$scriptExtraBeforeHtml = (isset($scriptExtrasHtml['before']) && $scriptExtrasHtml['before']) ? $scriptExtrasHtml['before'] : '';
|
||||
$scriptExtraAfterHtml = (isset($scriptExtrasHtml['after']) && $scriptExtrasHtml['after']) ? $scriptExtrasHtml['after'] : '';
|
||||
|
||||
if ($scriptExtraTranslationsValue || $scriptExtraCdataValue || $scriptExtraBeforeValue || $scriptExtraAfterValue) {
|
||||
if ( $scriptExtraCdataValue && self::isInlineJsCombineable($scriptExtraCdataValue) ) {
|
||||
$htmlSource = str_replace($scriptExtraCdataHtml, '', $htmlSource );
|
||||
}
|
||||
|
||||
if ($scriptExtraTranslationsValue) {
|
||||
$repsBefore = array(
|
||||
$scriptExtraTranslationsHtml => '',
|
||||
str_replace( '<script ', '<script data-wpacu-script-handle=\'' . $scriptHandle . '\' ', $scriptExtraTranslationsHtml ) => '',
|
||||
'>'."\n".$scriptExtraTranslationsValue."\n".'</script>' => '></script>',
|
||||
$scriptExtraTranslationsValue."\n" => ''
|
||||
);
|
||||
$htmlSource = str_replace(array_keys($repsBefore), array_values($repsBefore), $htmlSource );
|
||||
}
|
||||
|
||||
if ($scriptExtraBeforeValue && self::isInlineJsCombineable($scriptExtraBeforeValue)) {
|
||||
$repsBefore = array(
|
||||
$scriptExtraBeforeHtml => '',
|
||||
str_replace( '<script ', '<script data-wpacu-script-handle=\'' . $scriptHandle . '\' ', $scriptExtraBeforeHtml ) => '',
|
||||
'>'."\n".$scriptExtraBeforeValue."\n".'</script>' => '></script>',
|
||||
$scriptExtraBeforeValue."\n" => ''
|
||||
);
|
||||
$htmlSource = str_replace(array_keys($repsBefore), array_values($repsBefore), $htmlSource );
|
||||
}
|
||||
|
||||
if ($scriptExtraAfterValue && self::isInlineJsCombineable($scriptExtraAfterValue)) {
|
||||
$repsBefore = array(
|
||||
$scriptExtraAfterHtml => '',
|
||||
str_replace( '<script ', '<script data-wpacu-script-handle=\'' . $scriptHandle . '\' ', $scriptExtraAfterHtml ) => '',
|
||||
'>'."\n".$scriptExtraAfterValue."\n".'</script>' => '></script>',
|
||||
$scriptExtraAfterValue."\n" => ''
|
||||
);
|
||||
$htmlSource = str_replace(array_keys($repsBefore), array_values($repsBefore), $htmlSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, strip/replace the tag
|
||||
return str_replace( array($scriptTag."\n", $scriptTag), $replaceWith, $htmlSource );
|
||||
}
|
||||
|
||||
/**
|
||||
* This is to prevent certain inline JS to be appended to the combined JS files in order to avoid lots of disk space (sometimes a few GB) of JS combined files
|
||||
*
|
||||
* @param $jsInlineValue
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInlineJsCombineable($jsInlineValue)
|
||||
{
|
||||
// The common WordPress nonce
|
||||
if (strpos($jsInlineValue, 'nonce') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// WooCommerce Cart Fragments
|
||||
if (strpos($jsInlineValue, 'wc_cart_hash_') !== false && strpos($jsInlineValue, 'cart_hash_key') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (substr(trim($jsInlineValue), 0, 1) === '{' && substr(trim($jsInlineValue), -1, 1) === '}') {
|
||||
json_decode($jsInlineValue);
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return false; // it's a JSON format (e.g. type="application/json" from "wordpress-popular-posts" plugin)
|
||||
}
|
||||
}
|
||||
|
||||
return true; // default
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function proceedWithJsCombine()
|
||||
{
|
||||
// not on query string request (debugging purposes)
|
||||
if ( isset($_REQUEST['wpacu_no_js_combine']) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No JS files are combined in the Dashboard
|
||||
// Always in the front-end view
|
||||
// Do not combine if there's a POST request as there could be assets loading conditionally
|
||||
// that might not be needed when the page is accessed without POST, making the final JS file larger
|
||||
if (! empty($_POST) || is_admin()) {
|
||||
return false; // Do not combine
|
||||
}
|
||||
|
||||
// Only clean request URIs allowed (with few exceptions)
|
||||
if (strpos($_SERVER['REQUEST_URI'], '?') !== false) {
|
||||
// Exceptions
|
||||
if (! OptimizeCommon::loadOptimizedAssetsIfQueryStrings()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! OptimizeCommon::doCombineIsRegularPage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pluginSettings = Main::instance()->settings;
|
||||
|
||||
if ($pluginSettings['test_mode'] && ! Menu::userCanManageAssets()) {
|
||||
return false; // Do not combine anything if "Test Mode" is ON
|
||||
}
|
||||
|
||||
if ($pluginSettings['combine_loaded_js'] === '') {
|
||||
return false; // Do not combine
|
||||
}
|
||||
|
||||
if (OptimizeJs::isOptimizeJsEnabledByOtherParty('if_enabled')) {
|
||||
return false; // Do not combine (it's already enabled in other plugin)
|
||||
}
|
||||
|
||||
// "Minify HTML" from WP Rocket is sometimes stripping combined SCRIPT tags
|
||||
// Better uncombined then missing essential SCRIPT files
|
||||
if (Misc::isWpRocketMinifyHtmlEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if ( ($pluginSettings['combine_loaded_js'] === 'for_admin'
|
||||
|| $pluginSettings['combine_loaded_js_for_admin_only'] == 1)
|
||||
&& Menu::userCanManageAssets() ) {
|
||||
return true; // Do combine
|
||||
}
|
||||
*/
|
||||
|
||||
// "Apply it only for guest visitors (default)" is set; Do not combine if the user is logged in
|
||||
if ( $pluginSettings['combine_loaded_js_for'] === 'guests' && is_user_logged_in() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( in_array($pluginSettings['combine_loaded_js'], array('for_all', 1)) ) {
|
||||
return true; // Do combine
|
||||
}
|
||||
|
||||
// Finally, return false as none of the checks above matched
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
/**
|
||||
* Class DynamicLoadedAssets
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class DynamicLoadedAssets
|
||||
{
|
||||
/**
|
||||
* @param $from
|
||||
* @param $value
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public static function getAssetContentFrom($from, $value)
|
||||
{
|
||||
$assetContent = '';
|
||||
|
||||
if ($from === 'simple-custom-css') {
|
||||
/*
|
||||
* Special Case: "Simple Custom CSS" Plugin
|
||||
*
|
||||
* /?sccss=1
|
||||
*
|
||||
* As it is (no minification or optimization), it adds extra load time to the page
|
||||
* as the CSS is read via PHP and all the WP environment is loading
|
||||
*/
|
||||
if (! $assetContent = self::getSimpleCustomCss()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($from === 'dynamic') { // /? .php? etc.
|
||||
if (! OptimizeCommon::isSourceFromSameHost($value->src)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$response = wp_remote_get(
|
||||
$value->src
|
||||
);
|
||||
|
||||
if (wp_remote_retrieve_response_code($response) !== 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $assetContent = wp_remote_retrieve_body($response)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $assetContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Simple Custom CSS" (better retrieval, especially for localhost and password-protected sites)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getSimpleCustomCss()
|
||||
{
|
||||
$sccssOptions = get_option('sccss_settings');
|
||||
$sccssRawContent = isset($sccssOptions['sccss-content']) ? $sccssOptions['sccss-content'] : '';
|
||||
$cssContent = wp_kses($sccssRawContent, array('\'', '\"'));
|
||||
$cssContent = str_replace('>', '>', $cssContent);
|
||||
|
||||
return trim($cssContent);
|
||||
}
|
||||
}
|
@ -0,0 +1,764 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Misc;
|
||||
use WpAssetCleanUp\Plugin;
|
||||
|
||||
/**
|
||||
* Class FontsGoogle
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class FontsGoogle
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $containsStr = '//fonts.googleapis.com/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $matchesStr = '//fonts.googleapis.com/(css|icon)\?';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const NOSCRIPT_WEB_FONT_LOADER = '<span style="display: none;" data-name=wpacu-delimiter content="ASSET CLEANUP NOSCRIPT WEB FONT LOADER"></span>';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const COMBINED_LINK_DEL = '<span style="display: none;" data-name=wpacu-delimiter content="ASSET CLEANUP COMBINED LINK LOCATION"></span>';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (self::preventAnyChange()) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter('wp_resource_hints', array($this, 'resourceHints'), PHP_INT_MAX, 2);
|
||||
|
||||
add_action('wp_head', array($this, 'preloadFontFiles'), 1);
|
||||
add_action('wp_footer', static function() {
|
||||
if ( Plugin::preventAnyFrontendOptimization() || Main::isTestModeActive() || Main::instance()->settings['google_fonts_remove'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo self::NOSCRIPT_WEB_FONT_LOADER;
|
||||
}, PHP_INT_MAX);
|
||||
|
||||
add_filter('wpacu_html_source_after_optimization', static function($htmlSource) {
|
||||
// Is the mark still there and wasn't replaced? Strip it
|
||||
return str_replace(FontsGoogle::NOSCRIPT_WEB_FONT_LOADER, '', $htmlSource);
|
||||
});
|
||||
|
||||
add_action('init', function() {
|
||||
// don't apply any changes if not in the front-end view (e.g. Dashboard view)
|
||||
// or test mode is enabled and a guest user is accessing the page
|
||||
if ( Plugin::preventAnyFrontendOptimization() || Main::isTestModeActive() || Main::instance()->settings['google_fonts_remove'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter('style_loader_src', array($this, 'alterGoogleFontLink'));
|
||||
}, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $urls
|
||||
* @param $relationType
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function resourceHints($urls, $relationType)
|
||||
{
|
||||
// don't apply any changes if not in the front-end view (e.g. Dashboard view)
|
||||
// or test mode is enabled and a guest user is accessing the page
|
||||
if (is_admin() || Main::isTestModeActive() || Plugin::preventAnyFrontendOptimization()) {
|
||||
return $urls;
|
||||
}
|
||||
|
||||
// Are the Google Fonts removed? Do not add it and strip any existing ones
|
||||
if (! empty($urls) && Main::instance()->settings['google_fonts_remove']) {
|
||||
foreach ($urls as $urlKey => $urlValue) {
|
||||
if (is_string($urlValue) && ((stripos($urlValue, 'fonts.googleapis.com') !== false) || (stripos($urlValue, 'fonts.gstatic.com') !== false))) {
|
||||
unset($urls[$urlKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return $urls; // Finally, return the list after any removals
|
||||
}
|
||||
|
||||
// Google Fonts "preconnect"
|
||||
if ('preconnect' === $relationType
|
||||
&& ! Main::instance()->settings['google_fonts_remove'] // "Remove Google Fonts" has to be turned off
|
||||
&& Main::instance()->settings['google_fonts_preconnect']) { // Needs to be enabled within "Plugin Usage Preferences" in "Settings"
|
||||
$urls[] = array(
|
||||
'href' => 'https://fonts.gstatic.com/',
|
||||
'crossorigin'
|
||||
);
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function preloadFontFiles()
|
||||
{
|
||||
// don't apply any changes if not in the front-end view (e.g. Dashboard view)
|
||||
// or test mode is enabled and a guest user is accessing the page
|
||||
if ( Plugin::preventAnyFrontendOptimization() || Main::isTestModeActive() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $preloadFontFiles = trim(Main::instance()->settings['google_fonts_preload_files'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray = array();
|
||||
|
||||
if (strpos($preloadFontFiles, "\n") !== false) {
|
||||
foreach (explode("\n", $preloadFontFiles) as $preloadFontFile) {
|
||||
$preloadFontFile = trim($preloadFontFile);
|
||||
|
||||
if (! $preloadFontFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray[] = $preloadFontFile;
|
||||
}
|
||||
} else {
|
||||
$preloadFontFilesArray[] = $preloadFontFiles;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray = array_unique($preloadFontFilesArray);
|
||||
|
||||
$preloadFontFilesOutput = '';
|
||||
|
||||
// Finally, go through the list
|
||||
foreach ($preloadFontFilesArray as $preloadFontFile) {
|
||||
$preloadFontFilesOutput .= '<link rel="preload" as="font" href="'.esc_attr($preloadFontFile).'" data-wpacu-preload-font="1" crossorigin>'."\n";
|
||||
}
|
||||
|
||||
echo apply_filters('wpacu_preload_google_font_files_output', $preloadFontFilesOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return false|mixed|string|void
|
||||
*/
|
||||
public static function alterHtmlSource($htmlSource)
|
||||
{
|
||||
// don't apply any changes if not in the front-end view (e.g. Dashboard view)
|
||||
// or test mode is enabled and a guest user is accessing the page
|
||||
// or an AMP page is accessed
|
||||
if ( Plugin::preventAnyFrontendOptimization() || Main::isTestModeActive()) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove Google Fonts? Stop here as optimization is no longer relevant
|
||||
*/
|
||||
if (Main::instance()->settings['google_fonts_remove']) {
|
||||
return FontsGoogleRemove::cleanHtmlSource($htmlSource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimize Google Fonts
|
||||
*/
|
||||
if (stripos($htmlSource, self::$containsStr) !== false) {
|
||||
// Cleaner HTML Source
|
||||
$altHtmlSource = preg_replace( '@<(script|style|noscript)[^>]*?>.*?</\\1>@si', '', $htmlSource ); // strip irrelevant tags for the collection
|
||||
$altHtmlSource = preg_replace( '/<!--[^>]*' . preg_quote( self::$containsStr, '/' ) . '.*?-->/', '', $altHtmlSource ); // strip any comments containing the string
|
||||
|
||||
// Get all valid LINKs that have the $string within them
|
||||
preg_match_all( '#<link[^>]*' . self::$matchesStr . '.*(>)#Usmi', $altHtmlSource, $matchesFromLinkTags, PREG_SET_ORDER );
|
||||
|
||||
// Needs to match at least one to carry on with the replacements
|
||||
if ( isset( $matchesFromLinkTags[0] ) && ! empty( $matchesFromLinkTags[0] ) ) {
|
||||
if ( Main::instance()->settings['google_fonts_combine'] ) {
|
||||
/*
|
||||
* "Combine Google Fonts" IS enabled
|
||||
*/
|
||||
$finalCombinableLinks = $preloadedLinks = array();
|
||||
|
||||
foreach ( $matchesFromLinkTags as $linkTagArray ) {
|
||||
$linkTag = $finalLinkTag = trim( trim( $linkTagArray[0], '"\'' ) );
|
||||
|
||||
// Extra checks to make sure it's a valid LINK tag
|
||||
if ( ( strpos( $linkTag, "'" ) !== false && ( substr_count( $linkTag, "'" ) % 2 ) )
|
||||
|| ( strpos( $linkTag, '"' ) !== false && ( substr_count( $linkTag, '"' ) % 2 ) )
|
||||
|| ( trim( strip_tags( $linkTag ) ) !== '' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the CSS has any 'data-wpacu-skip' attribute; if it does, do not continue and leave it as it is (non-combined)
|
||||
if ( preg_match( '#data-wpacu-skip([=>/ ])#i', $linkTag ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$finalLinkHref = $linkHrefOriginal = Misc::getValueFromTag($linkTag);
|
||||
|
||||
// [START] Remove invalid requests with no font family
|
||||
$urlParse = parse_url( str_replace( '&', '&', $linkHrefOriginal ), PHP_URL_QUERY );
|
||||
parse_str( $urlParse, $qStr );
|
||||
|
||||
if ( isset( $qStr['family'] ) && ! $qStr['family'] ) {
|
||||
$htmlSource = str_replace( $linkTag, '', $htmlSource );
|
||||
continue;
|
||||
}
|
||||
// [END] Remove invalid requests with no font family
|
||||
|
||||
// If anything is set apart from '[none set]', proceed
|
||||
if ( Main::instance()->settings['google_fonts_display'] ) {
|
||||
$finalLinkHref = self::alterGoogleFontLink( $linkHrefOriginal );
|
||||
|
||||
if ( $finalLinkHref !== $linkHrefOriginal ) {
|
||||
$finalLinkTag = str_replace( $linkHrefOriginal, $finalLinkHref, $linkTag );
|
||||
|
||||
// Finally, alter the HTML source
|
||||
$htmlSource = str_replace( $linkTag, $finalLinkTag, $htmlSource );
|
||||
}
|
||||
}
|
||||
|
||||
if ( preg_match( '/rel=(["\'])preload(["\'])/i', $finalLinkTag )
|
||||
|| strpos( $finalLinkTag, 'data-wpacu-to-be-preloaded-basic' ) ) {
|
||||
$preloadedLinks[] = $finalLinkHref;
|
||||
}
|
||||
|
||||
$finalCombinableLinks[] = array( 'href' => $finalLinkHref, 'tag' => $finalLinkTag );
|
||||
}
|
||||
|
||||
$preloadedLinks = array_unique( $preloadedLinks );
|
||||
|
||||
// Remove data for preloaded LINKs
|
||||
if ( ! empty( $preloadedLinks ) ) {
|
||||
foreach ( $finalCombinableLinks as $fclIndex => $combinableLinkData ) {
|
||||
if ( in_array( $combinableLinkData['href'], $preloadedLinks ) ) {
|
||||
unset( $finalCombinableLinks[ $fclIndex ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$finalCombinableLinks = array_values( $finalCombinableLinks );
|
||||
|
||||
// Only proceed with the optimization/combine if there's obviously at least 2 combinable URL requests to Google Fonts
|
||||
// OR the loading type is different from render-blocking
|
||||
if ( Main::instance()->settings['google_fonts_combine_type'] || count( $finalCombinableLinks ) > 1 ) {
|
||||
$htmlSource = self::combineGoogleFontLinks( $finalCombinableLinks, $htmlSource );
|
||||
}
|
||||
} elseif (Main::instance()->settings['google_fonts_display']) {
|
||||
/*
|
||||
* "Combine Google Fonts" IS NOT enabled
|
||||
* Go through the links and apply any "font-display"
|
||||
*/
|
||||
foreach ( $matchesFromLinkTags as $linkTagArray ) {
|
||||
$linkTag = trim( trim( $linkTagArray[0], '"\'' ) );
|
||||
|
||||
// Extra checks to make sure it's a valid LINK tag
|
||||
if ( ( strpos( $linkTag, "'" ) !== false && ( substr_count( $linkTag, "'" ) % 2 ) )
|
||||
|| ( strpos( $linkTag, '"' ) !== false && ( substr_count( $linkTag, '"' ) % 2 ) )
|
||||
|| ( trim( strip_tags( $linkTag ) ) !== '' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the CSS has any 'data-wpacu-skip' attribute; if it does, do not continue and leave it as it is (non-altered)
|
||||
if ( preg_match( '#data-wpacu-skip([=>/ ])#i', $linkTag ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$linkHrefOriginal = Misc::getValueFromTag($linkTag);
|
||||
|
||||
// [START] Remove invalid requests with no font family
|
||||
$urlParse = parse_url( str_replace( '&', '&', $linkHrefOriginal ), PHP_URL_QUERY );
|
||||
parse_str( $urlParse, $qStr );
|
||||
|
||||
if ( isset( $qStr['family'] ) && ! $qStr['family'] ) {
|
||||
$htmlSource = str_replace( $linkTag, '', $htmlSource );
|
||||
continue;
|
||||
}
|
||||
// [END] Remove invalid requests with no font family
|
||||
|
||||
// If anything is set apart from '[none set]', proceed
|
||||
$newLinkHref = self::alterGoogleFontLink( $linkHrefOriginal );
|
||||
|
||||
if ( $newLinkHref !== $linkHrefOriginal ) {
|
||||
$finalLinkTag = str_replace( $linkHrefOriginal, $newLinkHref, $linkTag );
|
||||
|
||||
// Finally, alter the HTML source
|
||||
$htmlSource = str_replace( $linkTag, $finalLinkTag, $htmlSource );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "font-display: swap;" if enabled
|
||||
$htmlSource = self::alterGoogleFontUrlFromInlineStyleTags($htmlSource);
|
||||
|
||||
// Clear any traces
|
||||
return str_replace(self::NOSCRIPT_WEB_FONT_LOADER, '', $htmlSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $linkHrefOriginal
|
||||
* @param bool $escHtml
|
||||
* @param $alterFor
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function alterGoogleFontLink($linkHrefOriginal, $escHtml = true, $alterFor = 'css')
|
||||
{
|
||||
$isInVar = false; // The link is inside a variable with a JSON format
|
||||
|
||||
// Some special filtering here as some hosting environments (at least staging) behave funny with // inside SCRIPT tags
|
||||
if ($alterFor === 'js') {
|
||||
$containsStrNoSlashes = str_replace('/', '', self::$containsStr);
|
||||
$conditionOne = stripos($linkHrefOriginal, $containsStrNoSlashes) === false;
|
||||
|
||||
if (strpos($linkHrefOriginal, '\/') !== false) {
|
||||
$isInVar = true;
|
||||
}
|
||||
} else { // css (default)
|
||||
$conditionOne = stripos($linkHrefOriginal, self::$containsStr) === false;
|
||||
}
|
||||
|
||||
// Do not continue if it doesn't contain the right string, or it contains 'display=' or it does not contain 'family=' or there is no value set for "font-display"
|
||||
if ($conditionOne ||
|
||||
stripos($linkHrefOriginal, 'display=') !== false ||
|
||||
stripos($linkHrefOriginal, 'family=') === false ||
|
||||
! Main::instance()->settings['google_fonts_display']) {
|
||||
// Return original source
|
||||
return $linkHrefOriginal;
|
||||
}
|
||||
|
||||
$altLinkHref = str_replace('&', '&', $linkHrefOriginal);
|
||||
|
||||
if ($isInVar) {
|
||||
$altLinkHref = str_replace('\/', '/', $altLinkHref);
|
||||
}
|
||||
|
||||
$urlQuery = parse_url($altLinkHref, PHP_URL_QUERY);
|
||||
parse_str($urlQuery, $outputStr);
|
||||
|
||||
// Is there no "display" or there is, but it has an empty value? Append the one we have in the "Settings" - "Google Fonts"
|
||||
if ( ! isset($outputStr['display']) || (isset($outputStr['display']) && $outputStr['display'] === '') ) {
|
||||
$outputStr['display'] = Main::instance()->settings['google_fonts_display'];
|
||||
|
||||
list($linkHrefFirstPart) = explode('?', $linkHrefOriginal);
|
||||
|
||||
// Returned the updated source with the 'display' parameter appended to it
|
||||
$afterQuestionMark = http_build_query($outputStr);
|
||||
|
||||
if ($escHtml) {
|
||||
$afterQuestionMark = esc_attr($afterQuestionMark);
|
||||
}
|
||||
|
||||
return $linkHrefFirstPart . '?' . $afterQuestionMark;
|
||||
}
|
||||
|
||||
// Return original source
|
||||
return $linkHrefOriginal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function alterGoogleFontUrlFromInlineStyleTags($htmlSource)
|
||||
{
|
||||
if (! preg_match('/@import(\s+)url\(/i', $htmlSource)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
preg_match_all('#<\s*?style\b[^>]*>(.*?)</style\b[^>]*>#s', $htmlSource, $styleMatches, PREG_SET_ORDER);
|
||||
|
||||
if (empty($styleMatches)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
// Go through each STYLE tag
|
||||
foreach ($styleMatches as $styleInlineArray) {
|
||||
list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
|
||||
|
||||
// Check if the STYLE tag has any 'data-wpacu-skip' attribute; if it does, do not continue
|
||||
if (preg_match('#data-wpacu-skip([=>/ ])#i', $styleInlineTag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the content relevant?
|
||||
if (! preg_match('/@import(\s+|)(url|\(|\'|")/i', $styleInlineContent)
|
||||
|| stripos($styleInlineContent, 'fonts.googleapis.com') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do any alteration to the URL of the Google Font
|
||||
$newCssOutput = self::alterGoogleFontUrlFromCssContent($styleInlineTag);
|
||||
|
||||
$htmlSource = str_replace($styleInlineTag, $newCssOutput, $htmlSource);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cssContent
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function alterGoogleFontUrlFromCssContent($cssContent)
|
||||
{
|
||||
if (stripos($cssContent, 'fonts.googleapis.com') === false || ! Main::instance()->settings['google_fonts_display']) {
|
||||
return $cssContent;
|
||||
}
|
||||
|
||||
$regExps = array('/@import(\s+)url\((.*?)\)(|\s+)\;/i', '/@import(\s+|)(\(|\'|")(.*?)(\'|"|\))\;/i');
|
||||
|
||||
$newCssOutput = $cssContent;
|
||||
|
||||
foreach ($regExps as $regExpIndex => $regExpPattern) {
|
||||
preg_match_all($regExpPattern, $cssContent, $matchesFromInlineCode, PREG_SET_ORDER);
|
||||
|
||||
if (! empty($matchesFromInlineCode)) {
|
||||
foreach ($matchesFromInlineCode as $matchesFromInlineCodeArray) {
|
||||
$cssImportRule = $matchesFromInlineCodeArray[0];
|
||||
|
||||
if ($regExpIndex === 0) {
|
||||
$googleApisUrl = trim($matchesFromInlineCodeArray[2], '"\' ');
|
||||
} else {
|
||||
$googleApisUrl = trim($matchesFromInlineCodeArray[3], '"\' ');
|
||||
}
|
||||
|
||||
// It has to be a Google Fonts API link
|
||||
if (stripos($googleApisUrl, 'fonts.googleapis.com') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newGoogleApisUrl = self::alterGoogleFontLink($googleApisUrl, false);
|
||||
|
||||
if ($newGoogleApisUrl !== $googleApisUrl) {
|
||||
$newCssImportRule = str_replace($googleApisUrl, $newGoogleApisUrl, $cssImportRule);
|
||||
$newCssOutput = str_replace($cssImportRule, $newCssImportRule, $newCssOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $newCssOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $jsContent
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function alterGoogleFontUrlFromJsContent($jsContent)
|
||||
{
|
||||
if (stripos($jsContent, 'fonts.googleapis.com') === false) {
|
||||
return $jsContent;
|
||||
}
|
||||
|
||||
$newJsOutput = $jsContent;
|
||||
|
||||
preg_match_all('#fonts.googleapis.com(.*?)(["\'])#si', $jsContent, $matchesFromJsCode);
|
||||
|
||||
if (isset($matchesFromJsCode[0]) && ! empty($matchesFromJsCode)) {
|
||||
foreach ($matchesFromJsCode[0] as $match) {
|
||||
$matchRule = $match;
|
||||
$googleApisUrl = trim($match, '"\' ');
|
||||
|
||||
$newGoogleApisUrl = self::alterGoogleFontLink($googleApisUrl, false, 'js');
|
||||
if ($newGoogleApisUrl !== $googleApisUrl) {
|
||||
$newJsMatchOutput = str_replace($googleApisUrl, $newGoogleApisUrl, $matchRule);
|
||||
$newJsOutput = str_replace($matchRule, $newJsMatchOutput, $newJsOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for any "WebFontConfig = { google: { families: ['font-one', 'font-two'] } }" patterns
|
||||
if ( stripos( $jsContent, 'WebFontConfig' ) !== false
|
||||
&& preg_match_all( '#WebFontConfig(.*?)google(\s+|):(\s+|){(\s+|)families(\s+|):(?<families>.*?)]#s', $jsContent, $webFontConfigMatches )
|
||||
&& isset( $webFontConfigMatches['families'] ) && ! empty( $webFontConfigMatches['families'] )
|
||||
) {
|
||||
foreach ($webFontConfigMatches['families'] as $webFontConfigKey => $webFontConfigMatch) {
|
||||
$originalWholeMatch = $webFontConfigMatches[0][$webFontConfigKey];
|
||||
$familiesMatchOutput = trim($webFontConfigMatch);
|
||||
|
||||
// NO match or existing "display" parameter was found? Do not continue
|
||||
if (! $familiesMatchOutput || strpos($familiesMatchOutput, 'display=')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alter the matched string
|
||||
$familiesNewOutput = preg_replace('/([\'"])$/', '&display='.Main::instance()->settings['google_fonts_display'].'\\1', $familiesMatchOutput);
|
||||
$newWebFontConfigOutput = str_replace($familiesMatchOutput, $familiesNewOutput, $originalWholeMatch);
|
||||
|
||||
// Finally, do the replacement
|
||||
$newJsOutput = str_replace($originalWholeMatch, $newWebFontConfigOutput, $newJsOutput);
|
||||
}
|
||||
}
|
||||
|
||||
return $newJsOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $finalLinks
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return false|mixed|string|void
|
||||
*/
|
||||
public static function combineGoogleFontLinks($finalLinks, $htmlSource)
|
||||
{
|
||||
$fontsArray = array();
|
||||
|
||||
foreach ($finalLinks as $finalLinkIndex => $finalLinkData) {
|
||||
$finalLinkHref = $finalLinkData['href'];
|
||||
$finalLinkHref = str_replace('&', '&', $finalLinkHref);
|
||||
|
||||
$queries = parse_url($finalLinkHref, PHP_URL_QUERY);
|
||||
parse_str($queries, $fontQueries);
|
||||
|
||||
if (! array_key_exists('family', $fontQueries) || array_key_exists('text', $fontQueries)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strip the existing tag, leave a mark where the final combined LINK will be placed
|
||||
$stripTagWith = ($finalLinkIndex === 0) ? self::COMBINED_LINK_DEL : '';
|
||||
$finalLinkTag = $finalLinkData['tag'];
|
||||
|
||||
$htmlSource = str_ireplace(array($finalLinkTag."\n", $finalLinkTag), $stripTagWith, $htmlSource);
|
||||
|
||||
$family = trim($fontQueries['family']);
|
||||
$family = trim($family, '|');
|
||||
|
||||
if (! $family) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($family, '|') !== false) {
|
||||
// More than one family per request?
|
||||
foreach (explode('|', $family) as $familyOne) {
|
||||
if (strpos($familyOne, ':') !== false) {
|
||||
// They have types
|
||||
list ($familyRaw, $familyTypes) = explode(':', $familyOne);
|
||||
$fontsArray['families'][$familyRaw]['types'] = self::buildSortTypesList($familyTypes);
|
||||
} else {
|
||||
// They do not have types
|
||||
$familyRaw = $familyOne;
|
||||
$fontsArray['families'][$familyRaw]['types'] = false;
|
||||
}
|
||||
}
|
||||
} elseif (strpos($family, ':') !== false) {
|
||||
list ($familyRaw, $familyTypes) = explode(':', $family);
|
||||
$fontsArray['families'][$familyRaw]['types'] = self::buildSortTypesList($familyTypes);
|
||||
} else {
|
||||
$familyRaw = $family;
|
||||
$fontsArray['families'][$familyRaw]['types'] = false;
|
||||
}
|
||||
|
||||
if (array_key_exists('subset', $fontQueries)) {
|
||||
// More than one subset per request?
|
||||
if (strpos($fontQueries['subset'], ',') !== false) {
|
||||
$multipleSubsets = explode(',', trim($fontQueries['subset'], ','));
|
||||
|
||||
foreach ($multipleSubsets as $subset) {
|
||||
$fontsArray['subsets'][] = trim($subset);
|
||||
}
|
||||
} else {
|
||||
// Only one subset
|
||||
$fontsArray['subsets'][] = $fontQueries['subset'];
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('effect', $fontQueries)) {
|
||||
// More than one subset per request?
|
||||
if (strpos($fontQueries['effect'], '|') !== false) {
|
||||
$multipleSubsets = explode('|', trim($fontQueries['effect'], '|'));
|
||||
|
||||
foreach ($multipleSubsets as $subset) {
|
||||
$fontsArray['effects'][] = trim($subset);
|
||||
}
|
||||
} else {
|
||||
// Only one subset
|
||||
$fontsArray['effects'][] = $fontQueries['effect'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($fontsArray)) {
|
||||
$finalCombinedParameters = '';
|
||||
ksort($fontsArray['families']);
|
||||
|
||||
// Families
|
||||
foreach ($fontsArray['families'] as $familyRaw => $fontValues) {
|
||||
$finalCombinedParameters .= str_replace(' ', '+', $familyRaw);
|
||||
|
||||
// Any types? e.g. 400, 400italic, bold, etc.
|
||||
if (isset($fontValues['types']) && $fontValues['types'] !== false) {
|
||||
$finalCombinedParameters .= ':' . $fontValues['types'];
|
||||
}
|
||||
|
||||
$finalCombinedParameters .= '|';
|
||||
}
|
||||
|
||||
$finalCombinedParameters = trim($finalCombinedParameters, '|');
|
||||
|
||||
// Subsets
|
||||
if (isset($fontsArray['subsets']) && ! empty($fontsArray['subsets'])) {
|
||||
sort($fontsArray['subsets']);
|
||||
$finalCombinedParameters .= '&subset=' . implode(',', array_unique($fontsArray['subsets']));
|
||||
}
|
||||
|
||||
// Effects
|
||||
if (isset($fontsArray['effects']) && ! empty($fontsArray['effects'])) {
|
||||
sort($fontsArray['effects']);
|
||||
$finalCombinedParameters .= '&effect=' . implode('|', array_unique($fontsArray['effects']));
|
||||
}
|
||||
|
||||
if ($fontDisplay = Main::instance()->settings['google_fonts_display']) {
|
||||
$finalCombinedParameters .= '&display=' . $fontDisplay;
|
||||
}
|
||||
|
||||
$finalCombinedParameters = esc_attr($finalCombinedParameters);
|
||||
|
||||
// This is needed for both render-blocking and async (within NOSCRIPT tag as a fallback)
|
||||
$finalCombinedLink = <<<LINK
|
||||
<link rel='stylesheet' id='wpacu-combined-google-fonts-css' href='https://fonts.googleapis.com/css?family={$finalCombinedParameters}' type='text/css' media='all' />
|
||||
LINK;
|
||||
/*
|
||||
* Loading Type: Render-Blocking (Default)
|
||||
*/
|
||||
if (! Main::instance()->settings['google_fonts_combine_type']) {
|
||||
$finalCombinedLink .= "\n";
|
||||
$htmlSource = str_replace(self::COMBINED_LINK_DEL, apply_filters('wpacu_combined_google_fonts_link_tag', $finalCombinedLink), $htmlSource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading Type: Asynchronous via LINK preload with fallback
|
||||
*/
|
||||
if (Main::instance()->settings['google_fonts_combine_type'] === 'async_preload') {
|
||||
$finalPreloadCombinedLink = <<<LINK
|
||||
<link rel='preload' as="style" onload="this.onload=null;this.rel='stylesheet'" data-wpacu-preload-it-async='1' id='wpacu-combined-google-fonts-css-async-preload' href='https://fonts.googleapis.com/css?family={$finalCombinedParameters}' type='text/css' media='all' />
|
||||
LINK;
|
||||
$finalPreloadCombinedLink .= "\n".Misc::preloadAsyncCssFallbackOutput();
|
||||
|
||||
$htmlSource = str_replace(self::COMBINED_LINK_DEL, apply_filters('wpacu_combined_google_fonts_async_preload_link_tag', $finalPreloadCombinedLink), $htmlSource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading Type: Asynchronous via Web Font Loader (webfont.js) with fallback
|
||||
*/
|
||||
if (Main::instance()->settings['google_fonts_combine_type'] === 'async') { // Async via Web Font Loader
|
||||
$subSetsStr = '';
|
||||
|
||||
if (isset($fontsArray['subsets']) && ! empty($fontsArray['subsets'])) {
|
||||
sort($fontsArray['subsets']);
|
||||
$subSetsStr = implode(',', array_unique($fontsArray['subsets']));
|
||||
}
|
||||
|
||||
$wfConfigGoogleFamilies = array();
|
||||
|
||||
// Families
|
||||
$iCount = 0;
|
||||
|
||||
foreach ($fontsArray['families'] as $familyRaw => $fontValues) {
|
||||
$wfConfigGoogleFamily = str_replace(' ', '+', $familyRaw);
|
||||
|
||||
// Any types? e.g. 400, 400italic, bold, etc.
|
||||
$hasTypes = false;
|
||||
if (isset($fontValues['types']) && $fontValues['types']) {
|
||||
$wfConfigGoogleFamily .= ':'.$fontValues['types'];
|
||||
$hasTypes = true;
|
||||
}
|
||||
|
||||
if ($subSetsStr) {
|
||||
// If there are types, continue to use the comma delimiter
|
||||
$wfConfigGoogleFamily .= ($hasTypes ? ',' : ':') . $subSetsStr;
|
||||
}
|
||||
|
||||
// Append extra parameters to the last family from the list
|
||||
if ($iCount === count($fontsArray['families']) - 1) {
|
||||
// Effects
|
||||
if (isset($fontsArray['effects']) && ! empty($fontsArray['effects'])) {
|
||||
sort($fontsArray['effects']);
|
||||
$wfConfigGoogleFamily .= '&effect=' . implode('|', array_unique($fontsArray['effects']));
|
||||
}
|
||||
|
||||
if ($fontDisplay = Main::instance()->settings['google_fonts_display']) {
|
||||
$wfConfigGoogleFamily .= '&display=' . $fontDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
$wfConfigGoogleFamilies[] = "'".$wfConfigGoogleFamily."'";
|
||||
|
||||
$iCount++;
|
||||
}
|
||||
|
||||
$wfConfigGoogleFamiliesStr = '['.implode(',', $wfConfigGoogleFamilies).']';
|
||||
|
||||
$finalInlineTagWebFontConfig = '<script id=\'wpacu-google-fonts-async-load\' type=\'text/javascript\'>'."\n".'WebFontConfig={google:{families:'.$wfConfigGoogleFamiliesStr.'}};(function(wpacuD){var wpacuWf=wpacuD.createElement(\'script\'),wpacuS=wpacuD.scripts[0];wpacuWf.src=(\'https:\'===document.location.protocol?\'https\':\'http\')+\'://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js\';wpacuWf.async=!0;wpacuS.parentNode.insertBefore(wpacuWf,wpacuS)})(document);'."\n".'</script>';
|
||||
|
||||
$htmlSource = str_replace(
|
||||
array(
|
||||
self::COMBINED_LINK_DEL,
|
||||
self::NOSCRIPT_WEB_FONT_LOADER
|
||||
),
|
||||
array(
|
||||
apply_filters( 'wpacu_combined_google_fonts_inline_script_tag', $finalInlineTagWebFontConfig ),
|
||||
'<noscript>' . apply_filters( 'wpacu_combined_google_fonts_link_tag', $finalCombinedLink ) . '</noscript>' . "\n"
|
||||
),
|
||||
$htmlSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. 300, 400, 400italic, bold, etc.
|
||||
*
|
||||
* @param $types
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function buildSortTypesList($types)
|
||||
{
|
||||
$newTypes = array();
|
||||
|
||||
// More than one type per family?
|
||||
if (strpos($types, ',') !== false) {
|
||||
$multipleTypes = explode(',', trim($types, ','));
|
||||
|
||||
foreach ($multipleTypes as $type) {
|
||||
if (trim($type)) {
|
||||
$newTypes[] = trim($type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only one type per family
|
||||
$newTypes[] = $types;
|
||||
}
|
||||
|
||||
$newTypes = array_unique($newTypes);
|
||||
|
||||
sort($newTypes);
|
||||
|
||||
return implode(',', $newTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function preventAnyChange()
|
||||
{
|
||||
return defined( 'WPACU_ALLOW_ONLY_UNLOAD_RULES' ) && WPACU_ALLOW_ONLY_UNLOAD_RULES;
|
||||
}
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
/**
|
||||
* Class FontsGoogle
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class FontsGoogleRemove
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $stringsToCheck = array(
|
||||
'//fonts.googleapis.com',
|
||||
'//fonts.gstatic.com'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $possibleWebFontConfigCdnPatterns = array(
|
||||
'//ajax.googleapis.com/ajax/libs/webfont/(.*?)', // Google Apis
|
||||
'//cdnjs.cloudflare.com/ajax/libs/webfont/(.*?)', // Cloudflare
|
||||
'//cdn.jsdelivr.net/npm/webfontloader@(.*?)' // jsDELIVR
|
||||
);
|
||||
|
||||
/**
|
||||
* Called late from OptimizeCss after all other optimizations are done (e.g. minify, combine)
|
||||
*
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanHtmlSource($htmlSource)
|
||||
{
|
||||
$htmlSource = self::cleanLinkTags($htmlSource);
|
||||
$htmlSource = self::cleanFromInlineStyleTags($htmlSource);
|
||||
|
||||
return str_replace(FontsGoogle::NOSCRIPT_WEB_FONT_LOADER, '', $htmlSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanLinkTags($htmlSource)
|
||||
{
|
||||
// Do not continue if there is no single reference to the string we look for in the clean HTML source
|
||||
if (stripos($htmlSource, FontsGoogle::$containsStr) === false) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
// Get all valid LINKs that have the self::$stringsToCheck within them
|
||||
$strContainsArray = array_map(static function($containsStr) {
|
||||
return preg_quote($containsStr, '/');
|
||||
}, self::$stringsToCheck);
|
||||
|
||||
$strContainsFormat = implode('|', $strContainsArray);
|
||||
|
||||
preg_match_all('#<link[^>]*(' . $strContainsFormat . ').*(>)#Usmi', $htmlSource, $matchesFromLinkTags, PREG_SET_ORDER);
|
||||
|
||||
$stripLinksList = array();
|
||||
|
||||
// Needs to match at least one to carry on with the replacements
|
||||
if (isset($matchesFromLinkTags[0]) && ! empty($matchesFromLinkTags[0])) {
|
||||
foreach ($matchesFromLinkTags as $linkTagArray) {
|
||||
$linkTag = trim(trim($linkTagArray[0], '"\''));
|
||||
|
||||
if (strip_tags($linkTag) !== '') {
|
||||
continue; // Something might be funny there, make sure the tag is valid
|
||||
}
|
||||
|
||||
// Check if the Google Fonts CSS has any 'data-wpacu-skip' attribute; if it does, do not remove it
|
||||
if (preg_match('#data-wpacu-skip([=>/ ])#i', $linkTag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stripLinksList[$linkTag] = '';
|
||||
}
|
||||
|
||||
$htmlSource = strtr($htmlSource, $stripLinksList);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanFromInlineStyleTags($htmlSource)
|
||||
{
|
||||
if (! preg_match('/(;?)(@import (?<url>url\(|\()?(?P<quotes>["\'()]?).+?(?P=quotes)(?(url)\)));?/', $htmlSource)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
preg_match_all('#<\s*?style\b[^>]*>(.*?)</style\b[^>]*>#s', $htmlSource, $styleMatches, PREG_SET_ORDER);
|
||||
|
||||
if (empty($styleMatches)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
// Go through each STYLE tag
|
||||
foreach ($styleMatches as $styleInlineArray) {
|
||||
list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
|
||||
|
||||
// Check if the STYLE tag has any 'data-wpacu-skip' attribute; if it does, do not continue
|
||||
if (preg_match('#data-wpacu-skip([=>/ ])#i', $styleInlineTag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newStyleInlineTag = $styleInlineTag;
|
||||
$newStyleInlineContent = $styleInlineContent;
|
||||
|
||||
// Is the content relevant?
|
||||
preg_match_all('/(;?)(@import (?<url>url\(|\()?(?P<quotes>["\'()]?).+?(?P=quotes)(?(url)\)));?/', $styleInlineContent, $matches);
|
||||
|
||||
if (isset($matches[0]) && ! empty($matches[0])) {
|
||||
foreach ($matches[0] as $matchedImport) {
|
||||
$newStyleInlineContent = str_replace($matchedImport, '', $newStyleInlineContent);
|
||||
}
|
||||
|
||||
$newStyleInlineContent = trim($newStyleInlineContent);
|
||||
|
||||
// Is the STYLE tag empty after the @imports are removed? It happens on some websites; strip the tag, no point of having it empty
|
||||
if ($newStyleInlineContent === '') {
|
||||
$htmlSource = str_replace($styleInlineTag, '', $htmlSource);
|
||||
} else {
|
||||
$newStyleInlineTag = str_replace($styleInlineContent, $newStyleInlineContent, $styleInlineTag);
|
||||
$htmlSource = str_replace($styleInlineTag, $newStyleInlineTag, $htmlSource);
|
||||
}
|
||||
}
|
||||
|
||||
$styleTagAfterImportsCleaned = $newStyleInlineTag;
|
||||
$styleTagAfterFontFaceCleaned = trim(self::cleanFontFaceReferences($newStyleInlineContent));
|
||||
$newStyleInlineTag = str_replace($newStyleInlineContent, $styleTagAfterFontFaceCleaned, $newStyleInlineTag);
|
||||
|
||||
$htmlSource = str_replace($styleTagAfterImportsCleaned, $newStyleInlineTag, $htmlSource);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $importsAddToTop
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function stripGoogleApisImport($importsAddToTop)
|
||||
{
|
||||
// Remove any Google Fonts imports
|
||||
foreach ($importsAddToTop as $importKey => $importToPrepend) {
|
||||
if (stripos($importToPrepend, FontsGoogle::$containsStr) !== false) {
|
||||
unset($importsAddToTop[$importKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return $importsAddToTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* If "Google Font Remove" is active, strip its references from JavaScript code as well
|
||||
*
|
||||
* @param $jsContent
|
||||
*
|
||||
* @return string|string[]|null
|
||||
*/
|
||||
public static function stripReferencesFromJsCode($jsContent)
|
||||
{
|
||||
if (self::preventAnyChange()) {
|
||||
return $jsContent;
|
||||
}
|
||||
|
||||
$webFontConfigReferenceOne = "#src(\s+|)=(\s+|)(?<startDel>'|\")(\s+|)((http:|https:|)(".implode('|', self::$possibleWebFontConfigCdnPatterns).")(\s+|))(?<endDel>'|\")#si";
|
||||
|
||||
if (stripos($jsContent, 'WebFontConfig') !== false
|
||||
&& preg_match('/(WebFontConfig\.|\'|"|)google(\s+|)([\'":=])/i', $jsContent)
|
||||
&& preg_match_all($webFontConfigReferenceOne, $jsContent, $matches) && ! empty($matches)
|
||||
) {
|
||||
foreach ($matches[0] as $matchIndex => $matchRow) {
|
||||
$jsContent = str_replace(
|
||||
$matchRow,
|
||||
'src=' . $matches['startDel'][$matchIndex] . $matches['endDel'][$matchIndex] . ';/* Stripped by ' . WPACU_PLUGIN_TITLE . ' */',
|
||||
$jsContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$webFontConfigReferenceTwo = '#("|\')((http:|https:|)//fonts.googleapis.com/(.*?))("|\')#si';
|
||||
|
||||
if (preg_match($webFontConfigReferenceTwo, $jsContent)) {
|
||||
$jsContent = preg_replace($webFontConfigReferenceTwo, '\\1\\5', $jsContent);
|
||||
}
|
||||
|
||||
return $jsContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cssContent
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function cleanFontFaceReferences($cssContent)
|
||||
{
|
||||
if (self::preventAnyChange()) {
|
||||
return $cssContent;
|
||||
}
|
||||
|
||||
preg_match_all('#@font-face(|\s+){(.*?)}#si', $cssContent, $matchesFromCssCode, PREG_SET_ORDER);
|
||||
|
||||
if (! empty($matchesFromCssCode)) {
|
||||
foreach ($matchesFromCssCode as $matches) {
|
||||
$fontFaceSyntax = $matches[0];
|
||||
preg_match_all('/url(\s+|)\((?![\'"]?(?:data):)[\'"]?([^\'")]*)[\'"]?\)/i', $matches[0], $matchesFromUrlSyntax);
|
||||
|
||||
if (! empty($matchesFromUrlSyntax) && stripos(implode('', $matchesFromUrlSyntax[0]), '//fonts.gstatic.com/') !== false) {
|
||||
$cssContent = str_replace($fontFaceSyntax, '', $cssContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cssContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function preventAnyChange()
|
||||
{
|
||||
return defined( 'WPACU_ALLOW_ONLY_UNLOAD_RULES' ) && WPACU_ALLOW_ONLY_UNLOAD_RULES;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Plugin;
|
||||
|
||||
/**
|
||||
* Class LocalFonts
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class FontsLocal
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (self::preventAnyChange()) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action('wp_head', array($this, 'preloadFontFiles'), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function preloadFontFiles()
|
||||
{
|
||||
// AMP page or Test Mode? Do not print anything
|
||||
if ( Plugin::preventAnyFrontendOptimization() || Main::isTestModeActive() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $preloadFontFiles = trim(Main::instance()->settings['local_fonts_preload_files'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray = array();
|
||||
|
||||
if (strpos($preloadFontFiles, "\n") !== false) {
|
||||
foreach (explode("\n", $preloadFontFiles) as $preloadFontFile) {
|
||||
$preloadFontFile = trim($preloadFontFile);
|
||||
|
||||
if (! $preloadFontFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray[] = $preloadFontFile;
|
||||
}
|
||||
} else {
|
||||
$preloadFontFilesArray[] = $preloadFontFiles;
|
||||
}
|
||||
|
||||
$preloadFontFilesArray = array_unique($preloadFontFilesArray);
|
||||
|
||||
$preloadFontFilesOutput = '';
|
||||
|
||||
// Finally, go through the list
|
||||
foreach ($preloadFontFilesArray as $preloadFontFile) {
|
||||
$preloadFontFilesOutput .= '<link rel="preload" as="font" href="'.esc_attr($preloadFontFile).'" data-wpacu-preload-font="1" crossorigin>'."\n";
|
||||
}
|
||||
|
||||
echo apply_filters('wpacu_preload_local_font_files_output', $preloadFontFilesOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function preventAnyChange()
|
||||
{
|
||||
if (defined('WPACU_ALLOW_ONLY_UNLOAD_RULES') && WPACU_ALLOW_ONLY_UNLOAD_RULES) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,340 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Menu;
|
||||
use WpAssetCleanUp\MetaBoxes;
|
||||
use WpAssetCleanUp\Misc;
|
||||
|
||||
/**
|
||||
* Class MinifyCss
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class MinifyCss
|
||||
{
|
||||
/**
|
||||
* @param $cssContent
|
||||
* @param bool $forInlineStyle
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function applyMinification($cssContent, $forInlineStyle = false
|
||||
)
|
||||
{
|
||||
if (class_exists('\MatthiasMullie\Minify\CSS')) {
|
||||
$sha1OriginalContent = sha1($cssContent);
|
||||
$checkForAlreadyMinifiedShaOne = mb_strlen($cssContent) > 40000;
|
||||
|
||||
// Let's check if the content is already minified
|
||||
// Save resources as the minify process can take time if the content is very large
|
||||
// Limit the total number of entries tp 100: if it's more than that, it's likely because there's dynamic JS altering on every page load
|
||||
if ($checkForAlreadyMinifiedShaOne && OptimizeCommon::originalContentIsAlreadyMarkedAsMinified($sha1OriginalContent, 'styles')) {
|
||||
return $cssContent;
|
||||
}
|
||||
|
||||
$cssContentBeforeAnyBugChanges = $cssContent;
|
||||
|
||||
// [CUSTOM BUG FIX]
|
||||
// Encode the special matched content to avoid any wrong minification from the minifier
|
||||
$hasVarWithZeroUnit = false;
|
||||
|
||||
preg_match_all('#--([a-zA-Z0-9_-]+):(\s+)0(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)#', $cssContent, $cssVariablesMatches);
|
||||
|
||||
if (isset($cssVariablesMatches[0]) && ! empty($cssVariablesMatches[0])) {
|
||||
$hasVarWithZeroUnit = true;
|
||||
|
||||
foreach ($cssVariablesMatches[0] as $zeroUnitMatch) {
|
||||
$cssContent = str_replace( $zeroUnitMatch, '[wpacu]' . base64_encode( $zeroUnitMatch ) . '[/wpacu]', $cssContent );
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: If the content is something like "calc(50% - 22px) calc(50% - 22px);" then leave it as it is
|
||||
preg_match_all('#calc(|\s+)\((.*?)(;|})#si', $cssContent, $cssCalcMatches);
|
||||
|
||||
$multipleOrSpecificCalcMatches = array(); // with multiple calc() or with at least one calc() that contains new lines
|
||||
|
||||
if (isset($cssCalcMatches[0]) && ! empty($cssCalcMatches[0])) {
|
||||
foreach ($cssCalcMatches[0] as $cssCalcMatch) {
|
||||
if (substr_count($cssCalcMatch, 'calc') > 1 || strpos($cssCalcMatch, "\n") !== false) {
|
||||
$cssContent = str_replace( $cssCalcMatch, '[wpacu]' . base64_encode( $cssCalcMatch ) . '[/wpacu]', $cssContent );
|
||||
$multipleOrSpecificCalcMatches[] = $cssCalcMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [/CUSTOM BUG FIX]
|
||||
|
||||
$minifier = new \MatthiasMullie\Minify\CSS( $cssContent );
|
||||
|
||||
if ( $forInlineStyle ) {
|
||||
// If the minification is applied for inlined CSS (within STYLE) leave the background URLs unchanged as it sometimes lead to issues
|
||||
$minifier->setImportExtensions( array() );
|
||||
}
|
||||
|
||||
$minifiedContent = trim( $minifier->minify() );
|
||||
|
||||
// [CUSTOM BUG FIX]
|
||||
// Restore the original content
|
||||
if ($hasVarWithZeroUnit) {
|
||||
foreach ( $cssVariablesMatches[0] as $zeroUnitMatch ) {
|
||||
$zeroUnitMatchAlt = str_replace(': 0', ':0', $zeroUnitMatch); // remove the space
|
||||
$minifiedContent = str_replace( '[wpacu]' . base64_encode( $zeroUnitMatch ) . '[/wpacu]', $zeroUnitMatchAlt, $minifiedContent );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty($multipleOrSpecificCalcMatches) ) {
|
||||
foreach ( $multipleOrSpecificCalcMatches as $cssCalcMatch ) {
|
||||
$originalCssCalcMatch = $cssCalcMatch;
|
||||
$cssCalcMatch = preg_replace(array('#calc\(\s+#', '#\s+\);#'), array('calc(', ');'), $originalCssCalcMatch);
|
||||
$cssCalcMatch = str_replace(' ) calc(', ') calc(', $cssCalcMatch);
|
||||
$minifiedContent = str_replace( '[wpacu]' . base64_encode( $originalCssCalcMatch ) . '[/wpacu]', $cssCalcMatch, $minifiedContent );
|
||||
}
|
||||
}
|
||||
// [/CUSTOM BUG FIX]
|
||||
|
||||
// Is there any [wpacu] left? Hmm, the replacement wasn't alright. Make sure to use the original minified version
|
||||
if (strpos($minifiedContent, '[wpacu]') !== false && strpos($minifiedContent, '[/wpacu]') !== false) {
|
||||
$minifier = new \MatthiasMullie\Minify\CSS( $cssContentBeforeAnyBugChanges );
|
||||
|
||||
if ( $forInlineStyle ) {
|
||||
// If the minification is applied for inlined CSS (within STYLE) leave the background URLs unchanged as it sometimes leads to issues
|
||||
$minifier->setImportExtensions( array() );
|
||||
}
|
||||
|
||||
$minifiedContent = trim( $minifier->minify() );
|
||||
}
|
||||
|
||||
if ($checkForAlreadyMinifiedShaOne && $minifiedContent === $cssContent) {
|
||||
// If the resulting content is the same, mark it as minified to avoid the minify process next time
|
||||
OptimizeCommon::originalContentMarkAsAlreadyMinified( $sha1OriginalContent, 'styles' );
|
||||
}
|
||||
|
||||
return $minifiedContent;
|
||||
}
|
||||
|
||||
return $cssContent;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $href
|
||||
* @param string $handle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function skipMinify($href, $handle = '')
|
||||
{
|
||||
// Things like WP Fastest Cache Toolbar CSS shouldn't be minified and take up space on the server
|
||||
if ($handle !== '' && in_array($handle, Main::instance()->skipAssets['styles'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Some of these files (e.g. from Oxygen, WooCommerce) are already minified
|
||||
$regExps = array(
|
||||
'#/wp-content/plugins/wp-asset-clean-up(.*?).min.css#',
|
||||
|
||||
// Formidable Forms
|
||||
'#/wp-content/plugins/formidable/css/formidableforms.css#',
|
||||
|
||||
// Oxygen
|
||||
//'#/wp-content/plugins/oxygen/component-framework/oxygen.css#',
|
||||
|
||||
// WooCommerce
|
||||
'#/wp-content/plugins/woocommerce/assets/css/woocommerce-layout.css#',
|
||||
'#/wp-content/plugins/woocommerce/assets/css/woocommerce.css#',
|
||||
'#/wp-content/plugins/woocommerce/assets/css/woocommerce-smallscreen.css#',
|
||||
'#/wp-content/plugins/woocommerce/assets/css/blocks/style.css#',
|
||||
'#/wp-content/plugins/woocommerce/packages/woocommerce-blocks/build/style.css#',
|
||||
|
||||
// Google Site Kit: the files are already optimized
|
||||
'#/wp-content/plugins/google-site-kit/#',
|
||||
|
||||
// Other libraries from the core that end in .min.css
|
||||
'#/wp-includes/css/(.*?).min.css#',
|
||||
|
||||
// Files within /wp-content/uploads/ or /wp-content/cache/
|
||||
// Could belong to plugins such as "Elementor", "Oxygen" etc.
|
||||
'#/wp-content/uploads/elementor/(.*?).css#',
|
||||
'#/wp-content/uploads/oxygen/css/(.*?)-(.*?).css#',
|
||||
'#/wp-content/cache/(.*?).css#',
|
||||
|
||||
// Already minified, and it also has a random name making the cache folder make bigger
|
||||
'#/wp-content/bs-booster-cache/#',
|
||||
|
||||
);
|
||||
|
||||
$regExps = Misc::replaceRelPluginPath($regExps);
|
||||
|
||||
if (Main::instance()->settings['minify_loaded_css_exceptions'] !== '') {
|
||||
$loadedCssExceptionsPatterns = trim(Main::instance()->settings['minify_loaded_css_exceptions']);
|
||||
|
||||
if (strpos($loadedCssExceptionsPatterns, "\n")) {
|
||||
// Multiple values (one per line)
|
||||
foreach (explode("\n", $loadedCssExceptionsPatterns) as $loadedCssExceptionPattern) {
|
||||
$regExps[] = '#'.trim($loadedCssExceptionPattern).'#';
|
||||
}
|
||||
} else {
|
||||
// Only one value?
|
||||
$regExps[] = '#'.trim($loadedCssExceptionsPatterns).'#';
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($regExps as $regExp) {
|
||||
if ( preg_match( $regExp, $href ) || ( strpos($href, $regExp) !== false ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function minifyInlineStyleTags($htmlSource)
|
||||
{
|
||||
if (stripos($htmlSource, '<style') === false) {
|
||||
return $htmlSource; // no STYLE tags
|
||||
}
|
||||
|
||||
$skipTagsContaining = array(
|
||||
'data-wpacu-skip',
|
||||
'astra-theme-css-inline-css',
|
||||
'astra-edd-inline-css',
|
||||
'et-builder-module-design-cached-inline-styles',
|
||||
'fusion-stylesheet-inline-css',
|
||||
'woocommerce-general-inline-css',
|
||||
'woocommerce-inline-inline-css',
|
||||
'data-wpacu-own-inline-style',
|
||||
// Only shown to the admin, irrelevant for any optimization (save resources)
|
||||
'data-wpacu-inline-css-file'
|
||||
// already minified/optimized since the INLINE was generated from the cached file
|
||||
);
|
||||
|
||||
$fetchType = 'regex';
|
||||
|
||||
if ( $fetchType === 'regex' ) {
|
||||
preg_match_all( '@(<style[^>]*?>).*?</style>@si', $htmlSource, $matchesStyleTags, PREG_SET_ORDER );
|
||||
if ( $matchesStyleTags === null ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($matchesStyleTags as $matchedStyle) {
|
||||
if ( ! (isset($matchedStyle[0]) && $matchedStyle[0]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$originalTag = $matchedStyle[0];
|
||||
|
||||
if (substr($originalTag, -strlen('></style>')) === strtolower('></style>')) {
|
||||
// No empty STYLE tags
|
||||
continue;
|
||||
}
|
||||
|
||||
// No need to use extra resources as the tag is already minified
|
||||
if ( preg_match( '(' . implode( '|', $skipTagsContaining ) . ')', $originalTag ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tagOpen = $matchedStyle[1];
|
||||
|
||||
$withTagOpenStripped = substr($originalTag, strlen($tagOpen));
|
||||
$originalTagContents = substr($withTagOpenStripped, 0, -strlen('</style>'));
|
||||
|
||||
if ( $originalTagContents ) {
|
||||
$newTagContents = OptimizeCss::maybeAlterContentForInlineStyleTag( $originalTagContents, true, array( 'just_minify' ) );
|
||||
|
||||
// Only comments or no content added to the inline STYLE tag? Strip it completely to reduce the number of DOM elements
|
||||
if ( $newTagContents === '/**/' || ! $newTagContents ) {
|
||||
$htmlSource = str_replace( '>' . $originalTagContents . '</', '></', $htmlSource );
|
||||
|
||||
preg_match( '#<style.*?>#si', $originalTag, $matchFromStyle );
|
||||
|
||||
if ( isset( $matchFromStyle[0] ) && $styleTagWithoutContent = $matchFromStyle[0] ) {
|
||||
$styleTagWithoutContentAlt = str_ireplace( '"', '\'', $styleTagWithoutContent );
|
||||
$htmlSource = str_ireplace( array(
|
||||
$styleTagWithoutContent . '</style>',
|
||||
$styleTagWithoutContentAlt . '</style>'
|
||||
), '', $htmlSource );
|
||||
}
|
||||
} else {
|
||||
// It has content; do the replacement
|
||||
$htmlSource = str_replace(
|
||||
'>' . $originalTagContents . '</style>',
|
||||
'>' . $newTagContents . '</style>',
|
||||
$htmlSource
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMinifyCssEnabled()
|
||||
{
|
||||
if (defined('WPACU_IS_MINIFY_CSS_ENABLED')) {
|
||||
return WPACU_IS_MINIFY_CSS_ENABLED;
|
||||
}
|
||||
|
||||
// Request Minify On The Fly
|
||||
// It will preview the page with CSS minified
|
||||
// Only if the admin is logged-in as it uses more resources (CPU / Memory)
|
||||
if ( isset($_GET['wpacu_css_minify']) && Menu::userCanManageAssets() ) {
|
||||
self::isMinifyCssEnabledChecked('true');
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( isset($_REQUEST['wpacu_no_css_minify']) || // not on query string request (debugging purposes)
|
||||
is_admin() || // not for Dashboard view
|
||||
(! Main::instance()->settings['minify_loaded_css']) || // Minify CSS has to be Enabled
|
||||
(Main::instance()->settings['test_mode'] && ! Menu::userCanManageAssets()) ) { // Does not trigger if "Test Mode" is Enabled
|
||||
self::isMinifyCssEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
|
||||
$isSingularPage = defined('WPACU_CURRENT_PAGE_ID') && WPACU_CURRENT_PAGE_ID > 0 && is_singular();
|
||||
|
||||
if ($isSingularPage || Misc::isHomePage()) {
|
||||
// If "Do not minify CSS on this page" is checked in "Asset CleanUp: Options" side meta box
|
||||
if ($isSingularPage) {
|
||||
$pageOptions = MetaBoxes::getPageOptions( WPACU_CURRENT_PAGE_ID ); // Singular page
|
||||
} else {
|
||||
$pageOptions = MetaBoxes::getPageOptions(0, 'front_page'); // Home page
|
||||
}
|
||||
|
||||
if ( isset( $pageOptions['no_css_minify'] ) && $pageOptions['no_css_minify'] ) {
|
||||
self::isMinifyCssEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (OptimizeCss::isOptimizeCssEnabledByOtherParty('if_enabled')) {
|
||||
self::isMinifyCssEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
|
||||
self::isMinifyCssEnabledChecked('true');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public static function isMinifyCssEnabledChecked($value)
|
||||
{
|
||||
if (! defined('WPACU_IS_MINIFY_CSS_ENABLED')) {
|
||||
if ($value === 'true') {
|
||||
define( 'WPACU_IS_MINIFY_CSS_ENABLED', true );
|
||||
} elseif ($value === 'false') {
|
||||
define( 'WPACU_IS_MINIFY_CSS_ENABLED', false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp\OptimiseAssets;
|
||||
|
||||
use WpAssetCleanUp\Main;
|
||||
use WpAssetCleanUp\Menu;
|
||||
use WpAssetCleanUp\MetaBoxes;
|
||||
use WpAssetCleanUp\Misc;
|
||||
|
||||
/**
|
||||
* Class MinifyJs
|
||||
* @package WpAssetCleanUp\OptimiseAssets
|
||||
*/
|
||||
class MinifyJs
|
||||
{
|
||||
/**
|
||||
* @param $jsContent
|
||||
*
|
||||
* @return string|string[]|null
|
||||
*/
|
||||
public static function applyMinification($jsContent)
|
||||
{
|
||||
if (class_exists('\MatthiasMullie\Minify\JS')) {
|
||||
$sha1OriginalContent = sha1($jsContent);
|
||||
$checkForAlreadyMinifiedShaOne = mb_strlen($jsContent) > 40000;
|
||||
|
||||
// Let's check if the content is already minified
|
||||
// Save resources as the minify process can take time if the content is very large
|
||||
// Limit the total number of entries to 100: if it's more than that, it's likely because there's dynamic JS altering on every page load
|
||||
if ($checkForAlreadyMinifiedShaOne && OptimizeCommon::originalContentIsAlreadyMarkedAsMinified($sha1OriginalContent, 'scripts')) {
|
||||
return $jsContent;
|
||||
}
|
||||
|
||||
// Minify it
|
||||
$alreadyMinified = false; // default
|
||||
|
||||
$minifier = new \MatthiasMullie\Minify\JS($jsContent);
|
||||
$minifiedContent = trim($minifier->minify());
|
||||
|
||||
if (trim($minifiedContent) === trim(trim($jsContent, ';'))) {
|
||||
$minifiedContent = $jsContent; // consider them the same if only the ';' at the end was stripped (it doesn't worth the resources that would be used)
|
||||
$alreadyMinified = true;
|
||||
}
|
||||
|
||||
// If the resulting content is the same, mark it as minified to avoid the minify process next time
|
||||
if ($checkForAlreadyMinifiedShaOne && $alreadyMinified) {
|
||||
// If the resulting content is the same, mark it as minified to avoid the minify process next time
|
||||
OptimizeCommon::originalContentMarkAsAlreadyMinified( $sha1OriginalContent, 'scripts' );
|
||||
}
|
||||
|
||||
return $minifiedContent;
|
||||
}
|
||||
|
||||
return $jsContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $src
|
||||
* @param string $handle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function skipMinify($src, $handle = '')
|
||||
{
|
||||
// Things like WP Fastest Cache Toolbar JS shouldn't be minified and take up space on the server
|
||||
if ($handle !== '' && in_array($handle, Main::instance()->skipAssets['scripts'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$regExps = array(
|
||||
'#/wp-content/plugins/wp-asset-clean-up(.*?).js#',
|
||||
|
||||
// Other libraries from the core that end in .min.js
|
||||
'#/wp-includes/(.*?).min.js#',
|
||||
|
||||
// jQuery & jQuery Migrate
|
||||
'#/wp-includes/js/jquery/jquery.js#',
|
||||
'#/wp-includes/js/jquery/jquery-migrate.js#',
|
||||
|
||||
// Files within /wp-content/uploads/
|
||||
// Files within /wp-content/uploads/ or /wp-content/cache/
|
||||
// Could belong to plugins such as "Elementor, "Oxygen" etc.
|
||||
//'#/wp-content/uploads/(.*?).js#',
|
||||
'#/wp-content/cache/(.*?).js#',
|
||||
|
||||
// Already minified, and it also has a random name making the cache folder make bigger
|
||||
'#/wp-content/bs-booster-cache/#',
|
||||
|
||||
// Elementor .min.js
|
||||
'#/wp-content/plugins/elementor/assets/(.*?).min.js#',
|
||||
|
||||
// WooCommerce Assets
|
||||
'#/wp-content/plugins/woocommerce/assets/js/(.*?).min.js#',
|
||||
|
||||
// Google Site Kit
|
||||
// The files are already optimized (they just have comments once in a while)
|
||||
// Minifying them causes some errors, so better to leave them load as they are
|
||||
'#/wp-content/plugins/google-site-kit/#',
|
||||
|
||||
// TranslatePress Multilingual
|
||||
'#/translatepress-multilingual/assets/js/trp-editor.js#',
|
||||
|
||||
);
|
||||
|
||||
$regExps = Misc::replaceRelPluginPath($regExps);
|
||||
|
||||
if (Main::instance()->settings['minify_loaded_js_exceptions'] !== '') {
|
||||
$loadedJsExceptionsPatterns = trim(Main::instance()->settings['minify_loaded_js_exceptions']);
|
||||
|
||||
if (strpos($loadedJsExceptionsPatterns, "\n")) {
|
||||
// Multiple values (one per line)
|
||||
foreach (explode("\n", $loadedJsExceptionsPatterns) as $loadedJsExceptionPattern) {
|
||||
$regExps[] = '#'.trim($loadedJsExceptionPattern).'#';
|
||||
}
|
||||
} else {
|
||||
// Only one value?
|
||||
$regExps[] = '#'.trim($loadedJsExceptionsPatterns).'#';
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($regExps as $regExp) {
|
||||
if ( preg_match( $regExp, $src ) || ( strpos($src, $regExp) !== false ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function minifyInlineScriptTags($htmlSource)
|
||||
{
|
||||
if (stripos($htmlSource, '<script') === false) {
|
||||
return $htmlSource; // no SCRIPT tags, hmm
|
||||
}
|
||||
|
||||
$skipTagsContaining = array_map( static function ( $toMatch ) {
|
||||
return preg_quote($toMatch, '/');
|
||||
}, array(
|
||||
'data-wpacu-skip',
|
||||
'/* <![CDATA[ */', // added via wp_localize_script()
|
||||
'wpacu-google-fonts-async-load',
|
||||
'wpacu-preload-async-css-fallback',
|
||||
/* [wpacu_pro] */'data-wpacu-inline-js-file',/* [/wpacu_pro] */
|
||||
'document.body.prepend(wpacuLinkTag',
|
||||
'var wc_product_block_data = JSON.parse( decodeURIComponent(',
|
||||
'/(^|\s)(no-)?customize-support(?=\s|$)/', // WP Core
|
||||
'b[c] += ( window.postMessage && request ? \' \' : \' no-\' ) + cs;', // WP Core
|
||||
'data-wpacu-own-inline-script', // Only shown to the admin, irrelevant for any optimization (save resources)
|
||||
// [wpacu_pro]
|
||||
'data-wpacu-inline-js-file', // already minified/optimized since the INLINE was generated from the cached file
|
||||
// [/wpacu_pro]
|
||||
));
|
||||
|
||||
// Do not perform another \DOMDocument call if it was done already somewhere else (e.g. CombineJs)
|
||||
$fetchType = 'regex'; // 'regex' or 'dom'
|
||||
|
||||
if ($fetchType === 'regex') {
|
||||
preg_match_all( '@(<script[^>]*?>).*?</script>@si', $htmlSource, $matchesScriptTags, PREG_SET_ORDER );
|
||||
|
||||
if ( $matchesScriptTags === null ) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($matchesScriptTags as $matchedScript) {
|
||||
if (isset($matchedScript[0]) && $matchedScript[0]) {
|
||||
$originalTag = $matchedScript[0];
|
||||
|
||||
if (strpos($originalTag, 'src=') && strtolower(substr($originalTag, -strlen('></script>'))) === strtolower('></script>')) {
|
||||
// Only inline SCRIPT tags allowed
|
||||
continue;
|
||||
}
|
||||
|
||||
// No need to use extra resources as the tag is already minified
|
||||
if ( preg_match( '/(' . implode( '|', $skipTagsContaining ) . ')/', $originalTag ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only 'text/javascript' type is allowed for minification
|
||||
$scriptType = Misc::getValueFromTag($originalTag, 'type') ?: 'text/javascript'; // default
|
||||
|
||||
if ($scriptType !== 'text/javascript') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tagOpen = $matchedScript[1];
|
||||
$withTagOpenStripped = substr($originalTag, strlen($tagOpen));
|
||||
$originalTagContents = substr($withTagOpenStripped, 0, -strlen('</script>'));
|
||||
|
||||
$newTagContents = OptimizeJs::maybeAlterContentForInlineScriptTag( $originalTagContents, true );
|
||||
|
||||
if ( $newTagContents !== $originalTagContents ) {
|
||||
$htmlSource = str_ireplace( '>' . $originalTagContents . '</script', '>' . $newTagContents . '</script', $htmlSource );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMinifyJsEnabled()
|
||||
{
|
||||
if (defined('WPACU_IS_MINIFY_JS_ENABLED')) {
|
||||
return WPACU_IS_MINIFY_JS_ENABLED;
|
||||
}
|
||||
|
||||
// Request Minify On The Fly
|
||||
// It will preview the page with JS minified
|
||||
// Only if the admin is logged-in as it uses more resources (CPU / Memory)
|
||||
if ( isset($_GET['wpacu_js_minify']) && Menu::userCanManageAssets()) {
|
||||
self::isMinifyJsEnabledChecked('true');
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( isset($_REQUEST['wpacu_no_js_minify']) || // not on query string request (debugging purposes)
|
||||
is_admin() || // not for Dashboard view
|
||||
(! Main::instance()->settings['minify_loaded_js']) || // Minify JS has to be Enabled
|
||||
(Main::instance()->settings['test_mode'] && ! Menu::userCanManageAssets()) ) { // Does not trigger if "Test Mode" is Enabled
|
||||
self::isMinifyJsEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
|
||||
$isSingularPage = defined('WPACU_CURRENT_PAGE_ID') && WPACU_CURRENT_PAGE_ID > 0 && is_singular();
|
||||
|
||||
if ($isSingularPage || Misc::isHomePage()) {
|
||||
// If "Do not minify JS on this page" is checked in "Asset CleanUp: Options" side meta box
|
||||
if ($isSingularPage) {
|
||||
$pageOptions = MetaBoxes::getPageOptions( WPACU_CURRENT_PAGE_ID ); // Singular page
|
||||
} else {
|
||||
$pageOptions = MetaBoxes::getPageOptions(0, 'front_page'); // Home page
|
||||
}
|
||||
|
||||
if ( isset( $pageOptions['no_js_minify'] ) && $pageOptions['no_js_minify'] ) {
|
||||
self::isMinifyJsEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (OptimizeJs::isOptimizeJsEnabledByOtherParty('if_enabled')) {
|
||||
self::isMinifyJsEnabledChecked('false');
|
||||
return false;
|
||||
}
|
||||
|
||||
self::isMinifyJsEnabledChecked('true');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public static function isMinifyJsEnabledChecked($value)
|
||||
{
|
||||
if (! defined('WPACU_IS_MINIFY_JS_ENABLED')) {
|
||||
if ($value === 'true') {
|
||||
define( 'WPACU_IS_MINIFY_JS_ENABLED', true );
|
||||
} elseif ($value === 'false') {
|
||||
define( 'WPACU_IS_MINIFY_JS_ENABLED', false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1016
wp-content/plugins/wp-asset-clean-up/classes/Overview.php
Normal file
1016
wp-content/plugins/wp-asset-clean-up/classes/Overview.php
Normal file
File diff suppressed because it is too large
Load Diff
1033
wp-content/plugins/wp-asset-clean-up/classes/OwnAssets.php
Normal file
1033
wp-content/plugins/wp-asset-clean-up/classes/OwnAssets.php
Normal file
File diff suppressed because it is too large
Load Diff
446
wp-content/plugins/wp-asset-clean-up/classes/Plugin.php
Normal file
446
wp-content/plugins/wp-asset-clean-up/classes/Plugin.php
Normal file
@ -0,0 +1,446 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
|
||||
|
||||
/**
|
||||
* Class Plugin
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Plugin
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const RATE_URL = 'https://wordpress.org/support/plugin/wp-asset-clean-up/reviews/#new-post';
|
||||
|
||||
/**
|
||||
* Plugin constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
register_activation_hook(WPACU_PLUGIN_FILE, array($this, 'whenActivated'));
|
||||
register_deactivation_hook(WPACU_PLUGIN_FILE, array($this, 'whenDeactivated'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
// After fist time activation or in specific situations within the Dashboard
|
||||
add_action('admin_init', array($this, 'adminInit'));
|
||||
|
||||
// [wpacu_lite]
|
||||
// Admin footer text: Ask the user to review the plugin
|
||||
add_filter('admin_footer_text', array($this, 'adminFooterText'), 1, 1);
|
||||
// [/wpacu_lite]
|
||||
|
||||
// Show default action links: "Getting Started", "Settings"
|
||||
add_filter('plugin_action_links_'.WPACU_PLUGIN_BASE, array($this, 'addActionLinksInPluginsPage'));
|
||||
|
||||
}
|
||||
|
||||
// [wpacu_lite]
|
||||
/**
|
||||
* @param $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function adminFooterText($text)
|
||||
{
|
||||
if (Menu::isPluginPage()) {
|
||||
$text = sprintf(__('Thank you for using %s', 'wp-asset-clean-up'), WPACU_PLUGIN_TITLE.' v'.WPACU_PLUGIN_VERSION)
|
||||
. ' <span class="dashicons dashicons-smiley"></span> ';
|
||||
|
||||
$text .= sprintf(
|
||||
__('If you like it, please %s<strong>rate</strong> %s%s %s on WordPress.org to help me spread the word to the community.', 'wp-asset-clean-up'),
|
||||
'<a target="_blank" href="'.self::RATE_URL.'">',
|
||||
WPACU_PLUGIN_TITLE,
|
||||
'</a>',
|
||||
'<a target="_blank" href="'.self::RATE_URL.'"><span class="dashicons dashicons-wpacu dashicons-star-filled"></span><span class="dashicons dashicons-wpacu dashicons-star-filled"></span><span class="dashicons dashicons-wpacu dashicons-star-filled"></span><span class="dashicons dashicons-wpacu dashicons-star-filled"></span><span class="dashicons dashicons-wpacu dashicons-star-filled"></span></a>'
|
||||
);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
// [/wpacu_lite]
|
||||
|
||||
/**
|
||||
* Actions taken when the plugin is activated
|
||||
*/
|
||||
public function whenActivated()
|
||||
{
|
||||
if (WPACU_WRONG_PHP_VERSION === 'true') {
|
||||
$recordMsg = __( '"Asset CleanUp" plugin has not been activated because the PHP version used on this server is below 5.6.',
|
||||
'wp-asset-clean-up' );
|
||||
deactivate_plugins( WPACU_PLUGIN_BASE );
|
||||
error_log( $recordMsg );
|
||||
wp_die($recordMsg);
|
||||
}
|
||||
|
||||
// Prepare for the redirection to the WPACU_ADMIN_PAGE_ID_START plugin page
|
||||
// If there is no record that the plugin was already activated at least once
|
||||
if ( ! get_option(WPACU_PLUGIN_ID.'_first_usage') ) {
|
||||
set_transient(WPACU_PLUGIN_ID . '_redirect_after_activation', 1, 15);
|
||||
|
||||
// Make a record when Asset CleanUp (Pro) is used for the first time
|
||||
// In case this is the first time the plugin is activated
|
||||
self::triggerFirstUsage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Could be /wp-content/uploads/ if constant WPACU_CACHE_DIR was used
|
||||
*
|
||||
* /wp-content/cache/asset-cleanup/
|
||||
* /wp-content/cache/asset-cleanup/index.php
|
||||
* /wp-content/cache/asset-cleanup/.htaccess
|
||||
*
|
||||
* /wp-content/cache/asset-cleanup/css/
|
||||
* /wp-content/cache/asset-cleanup/css/item/
|
||||
* /wp-content/cache/asset-cleanup/css/index.php
|
||||
*
|
||||
* /wp-content/cache/asset-cleanup/js/
|
||||
* /wp-content/cache/asset-cleanup/js/item/
|
||||
* /wp-content/cache/asset-cleanup/js/index.php
|
||||
*
|
||||
*/
|
||||
self::createCacheFoldersFiles(array('css','js'));
|
||||
|
||||
// Do not apply plugin's settings/rules on WooCommerce/EDD Checkout/Cart pages
|
||||
if (function_exists('wc_get_page_id')) {
|
||||
if ($wooCheckOutPageId = wc_get_page_id('checkout')) {
|
||||
Misc::doNotApplyOptimizationOnPage($wooCheckOutPageId);
|
||||
}
|
||||
|
||||
if ($wooCartPageId = wc_get_page_id('cart')) {
|
||||
Misc::doNotApplyOptimizationOnPage($wooCartPageId);
|
||||
}
|
||||
}
|
||||
|
||||
if (function_exists('edd_get_option') && $eddPurchasePage = edd_get_option('purchase_page', '')) {
|
||||
Misc::doNotApplyOptimizationOnPage($eddPurchasePage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions taken when the plugin is deactivated
|
||||
*/
|
||||
public function whenDeactivated()
|
||||
{
|
||||
// Clear traces of the plugin which are re-generated once the plugin is enabled
|
||||
// This is good when the admin wants to completely uninstall the plugin
|
||||
self::clearAllTransients();
|
||||
self::removeCacheDirWithoutAssets();
|
||||
|
||||
// Clear other plugin's cache (if they are active)
|
||||
OptimizeCommon::clearOtherPluginsCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all plugin's transients, this is usually done when the plugin is deactivated
|
||||
*/
|
||||
public static function clearAllTransients()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
// Remove all transients
|
||||
$transientLikes = array(
|
||||
'_transient_wpacu_',
|
||||
'_transient_'.WPACU_PLUGIN_ID.'_'
|
||||
);
|
||||
|
||||
$transientLikesSql = '';
|
||||
|
||||
foreach ($transientLikes as $transientLike) {
|
||||
$transientLikesSql .= " option_name LIKE '".$transientLike."%' OR ";
|
||||
}
|
||||
|
||||
$transientLikesSql = rtrim($transientLikesSql, ' OR ');
|
||||
|
||||
$sqlQuery = <<<SQL
|
||||
SELECT option_name FROM `{$wpdb->prefix}options` WHERE {$transientLikesSql}
|
||||
SQL;
|
||||
$transientsToClear = $wpdb->get_col($sqlQuery);
|
||||
|
||||
if (! empty($transientsToClear)) {
|
||||
foreach ( $transientsToClear as $transientToClear ) {
|
||||
$transientNameToClear = str_replace( '_transient_', '', $transientToClear );
|
||||
delete_transient( $transientNameToClear );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is usually triggered when the plugin is deactivated
|
||||
* If the caching directory doesn't have any CSS/JS left, it will clear itself
|
||||
* The admin might want to clear all traces of the plugin
|
||||
* If the plugin is re-activated, the caching directory will be re-created automatically
|
||||
*/
|
||||
public static function removeCacheDirWithoutAssets()
|
||||
{
|
||||
$pathToCacheDir = WP_CONTENT_DIR . OptimizeCommon::getRelPathPluginCacheDir();
|
||||
|
||||
if (! is_dir($pathToCacheDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pathToCacheDirCss = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir();
|
||||
$pathToCacheDirJs = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir();
|
||||
|
||||
$allCssFiles = glob( $pathToCacheDirCss . '**/*.css' );
|
||||
$allJsFiles = glob( $pathToCacheDirJs . '**/*.js' );
|
||||
|
||||
// Only valid when there's no CSS or JS (not one single file) there
|
||||
if ( count( $allCssFiles ) === 0 && count( $allJsFiles ) === 0 ) {
|
||||
$dirItems = new \RecursiveDirectoryIterator( $pathToCacheDir );
|
||||
|
||||
$allDirs = array($pathToCacheDir);
|
||||
|
||||
// First, remove the files
|
||||
foreach ( new \RecursiveIteratorIterator( $dirItems, \RecursiveIteratorIterator::SELF_FIRST,
|
||||
\RecursiveIteratorIterator::CATCH_GET_CHILD ) as $item) {
|
||||
if (is_dir($item)) {
|
||||
$allDirs[] = $item;
|
||||
} else {
|
||||
@unlink($item);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty($allDirs) ) {
|
||||
usort( $allDirs, static function( $a, $b ) {
|
||||
return strlen( $b ) - strlen( $a );
|
||||
} );
|
||||
|
||||
// Then, remove the empty dirs in descending order (up to the root)
|
||||
foreach ($allDirs as $dir) {
|
||||
Misc::rmDir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $assetTypes
|
||||
*/
|
||||
public static function createCacheFoldersFiles($assetTypes)
|
||||
{
|
||||
foreach ($assetTypes as $assetType) {
|
||||
if ($assetType === 'css') {
|
||||
$cacheDir = WP_CONTENT_DIR . OptimiseAssets\OptimizeCss::getRelPathCssCacheDir();
|
||||
} elseif ($assetType === 'js') {
|
||||
$cacheDir = WP_CONTENT_DIR . OptimiseAssets\OptimizeJs::getRelPathJsCacheDir();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
$emptyPhpFileContents = <<<TEXT
|
||||
<?php
|
||||
// Silence is golden.
|
||||
TEXT;
|
||||
|
||||
$htAccessContents = <<<HTACCESS
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
HTACCESS;
|
||||
|
||||
if ( ! is_dir( $cacheDir ) ) {
|
||||
@mkdir( $cacheDir, FS_CHMOD_DIR, true );
|
||||
}
|
||||
|
||||
if ( ! is_file( $cacheDir . 'index.php' ) ) {
|
||||
// /wp-content/cache/asset-cleanup/cache/(css|js)/index.php
|
||||
FileSystem::filePutContents( $cacheDir . 'index.php', $emptyPhpFileContents );
|
||||
}
|
||||
|
||||
if ( ! is_dir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir ) ) {
|
||||
// /wp-content/cache/asset-cleanup/cache/(css|js)/item/
|
||||
@mkdir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir, FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
// For large inline STYLE & SCRIPT tags
|
||||
if ( ! is_dir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline' ) ) {
|
||||
// /wp-content/cache/asset-cleanup/cache/(css|js)/item/inline/
|
||||
@mkdir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline', FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
if ( ! is_file( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline/index.php' ) ) {
|
||||
// /wp-content/cache/asset-cleanup/cache/(css|js)/item/inline/index.php
|
||||
FileSystem::filePutContents( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline/index.php', $emptyPhpFileContents );
|
||||
}
|
||||
|
||||
$htAccessFilePath = dirname( $cacheDir ) . '/.htaccess';
|
||||
|
||||
if ( ! is_file( $htAccessFilePath ) ) {
|
||||
// /wp-content/cache/asset-cleanup/.htaccess
|
||||
FileSystem::filePutContents( $htAccessFilePath, $htAccessContents );
|
||||
}
|
||||
|
||||
if ( ! is_file( dirname( $cacheDir ) . '/index.php' ) ) {
|
||||
// /wp-content/cache/asset-cleanup/index.php
|
||||
FileSystem::filePutContents( dirname( $cacheDir ) . '/index.php', $emptyPhpFileContents );
|
||||
}
|
||||
}
|
||||
|
||||
// Storage directory for JSON/TEXT files (information purpose)
|
||||
$storageDir = WP_CONTENT_DIR . OptimiseAssets\OptimizeCommon::getRelPathPluginCacheDir() . '_storage/';
|
||||
|
||||
if ( ! is_dir($storageDir . OptimizeCommon::$optimizedSingleFilesDir) ) {
|
||||
@mkdir( $storageDir . OptimizeCommon::$optimizedSingleFilesDir, FS_CHMOD_DIR, true );
|
||||
}
|
||||
|
||||
$siteStorageCache = $storageDir.'/'.str_replace(array('https://', 'http://', '//'), '', site_url());
|
||||
|
||||
if ( ! is_dir($storageDir) ) {
|
||||
@mkdir( $siteStorageCache, FS_CHMOD_DIR, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function adminInit()
|
||||
{
|
||||
if ( // If this condition does not match, do not make the extra DB calls to "options" table to save resources
|
||||
isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], '/plugins.php') !== false &&
|
||||
get_transient(WPACU_PLUGIN_ID . '_redirect_after_activation') ) {
|
||||
// Remove it as only one redirect is needed (first time the plugin is activated)
|
||||
delete_transient(WPACU_PLUGIN_ID . '_redirect_after_activation');
|
||||
|
||||
// Do the 'first activation time' redirection
|
||||
wp_redirect(admin_url('admin.php?page=' . WPACU_ADMIN_PAGE_ID_START));
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $links
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function addActionLinksInPluginsPage($links)
|
||||
{
|
||||
$links['getting_started'] = '<a href="admin.php?page=' . WPACU_PLUGIN_ID . '_getting_started">'.__('Getting Started', 'wp-asset-clean-up').'</a>';
|
||||
$links['settings'] = '<a href="admin.php?page=' . WPACU_PLUGIN_ID . '_settings">'.__('Settings', 'wp-asset-clean-up').'</a>';
|
||||
|
||||
// [wpacu_lite]
|
||||
$allPlugins = get_plugins();
|
||||
|
||||
// If the Pro version is not installed (active or not), show the upgrade link
|
||||
if (! array_key_exists('wp-asset-clean-up-pro/wpacu.php', $allPlugins)) {
|
||||
$links['go_pro'] = '<a target="_blank" style="font-weight: bold;" href="'.apply_filters('wpacu_go_pro_affiliate_link', WPACU_PLUGIN_GO_PRO_URL).'">'.__('Go Pro', 'wp-asset-clean-up').'</a>';
|
||||
}
|
||||
// [/wpacu_lite]
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a record when Asset CleanUp (Pro) is used for the first time (if it's not there already)
|
||||
*/
|
||||
public static function triggerFirstUsage()
|
||||
{
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_first_usage', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* This works like /?wpacu_no_load with a fundamental difference:
|
||||
* It needs to be triggered through a very early 'init' / 'setup_theme' action hook after all plugins are loaded, thus it can't be used in /early-triggers.php
|
||||
* e.g. in situations when the page is an AMP one, prevent any changes to the HTML source by Asset CleanUp (Pro)
|
||||
*
|
||||
* @param string $tagActionName
|
||||
* @param string $htmlSource
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function preventAnyFrontendOptimization($tagActionName = '', $htmlSource = '')
|
||||
{
|
||||
// Only relevant if all the plugins are already loaded
|
||||
// and in the front-end view
|
||||
if (! defined('WPACU_ALL_ACTIVE_PLUGINS_LOADED') || is_admin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perhaps the editor from "Pro" (theme.co) is on
|
||||
if (apply_filters('wpacu_prevent_any_frontend_optimization', false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// e.g. /amp/ - /amp? - /amp/? - /?amp or ending in /amp
|
||||
$isAmpInRequestUri = ( (isset($_SERVER['REQUEST_URI']) && (preg_match('/(\/amp$|\/amp\?)|(\/amp\/|\/amp\/\?)/', $_SERVER['REQUEST_URI'])))
|
||||
|| isset($_GET['amp']) );
|
||||
|
||||
// Is it an AMP endpoint?
|
||||
if ( ($isAmpInRequestUri && Misc::isPluginActive('accelerated-mobile-pages/accelerated-mobile-pages.php')) // "AMP for WP – Accelerated Mobile Pages"
|
||||
|| ($isAmpInRequestUri && Misc::isPluginActive('amp/amp.php')) // "AMP – WordPress plugin"
|
||||
|| ((function_exists('is_wp_amp') && Misc::isPluginActive('wp-amp/wp-amp.php') && is_wp_amp())) // "WP AMP — Accelerated Mobile Pages for WordPress and WooCommerce" (Premium plugin)
|
||||
) {
|
||||
return true; // do not print anything on an AMP page
|
||||
}
|
||||
|
||||
// Some pages are AMP but their URI does not end in /amp
|
||||
if ( ! defined('WPACU_DO_EXTRA_CHECKS_FOR_AMP') &&
|
||||
( Misc::isPluginActive('accelerated-mobile-pages/accelerated-mobile-pages.php')
|
||||
|| Misc::isPluginActive('amp/amp.php')
|
||||
|| Misc::isPluginActive('wp-amp/wp-amp.php') )
|
||||
) {
|
||||
define('WPACU_DO_EXTRA_CHECKS_FOR_AMP', true);
|
||||
}
|
||||
|
||||
if ( isset($_GET['wpacu_clean_load']) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// $tagActionName needs to be different from 'parse_query' because is_singular() would trigger too soon and cause notice errors
|
||||
// Has the following page option set: "Do not apply any front-end optimization on this page (this includes any changes related to CSS/JS files)"
|
||||
if ($tagActionName !== 'parse_query' && MetaBoxes::hasNoFrontendOptimizationPageOption()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// e.g. it could be JS content loaded dynamically such as /?wpml-app=ate-widget
|
||||
// in this case, any Asset CleanUp alteration of the content should be avoided
|
||||
// often, the code below is not reached as extra measures are taken before if well known plugins are used
|
||||
if ($htmlSource !== '') {
|
||||
$startsWithPassed = $endsWithPassed = false;
|
||||
|
||||
// More common delimiters can be added with time
|
||||
// This is just an extra measure to prevent possible empty pages due to lots of memory used in case a possible JavaScript output is too large
|
||||
$startsWithAnyFromTheList = array(
|
||||
'/*!',
|
||||
'(function()'
|
||||
);
|
||||
|
||||
$endsWithAnyFromTheList = array(
|
||||
');',
|
||||
')'
|
||||
);
|
||||
|
||||
// Possible JS content
|
||||
foreach ($startsWithAnyFromTheList as $startsWithString) {
|
||||
if (substr(trim($htmlSource), 0, strlen($startsWithString)) === $startsWithString) {
|
||||
$startsWithPassed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($startsWithPassed) {
|
||||
foreach ($endsWithAnyFromTheList as $endsWithString) {
|
||||
if (substr(trim($htmlSource), -strlen($endsWithString)) === $endsWithString) {
|
||||
$endsWithPassed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($startsWithPassed && $endsWithPassed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
301
wp-content/plugins/wp-asset-clean-up/classes/PluginReview.php
Normal file
301
wp-content/plugins/wp-asset-clean-up/classes/PluginReview.php
Normal file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class PluginReview
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class PluginReview
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $showReviewNotice;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public static $closingReasons = array('maybe_later', 'never_show_it');
|
||||
|
||||
/**
|
||||
* PluginReview constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Notice to rate plugin on WordPress.org based on specific conditions
|
||||
add_action('admin_notices', array($this, 'ratePluginNoticeOutput'));
|
||||
|
||||
// Close the notice when action is taken by AJAX call
|
||||
add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_close_review_notice', array($this, 'ajaxCloseReviewNoticeCallback'));
|
||||
|
||||
// Close the notice when action is taken by page reload (e.g. rate it later or never show the notice again)
|
||||
add_action('admin_post_' . WPACU_PLUGIN_ID . '_close_review_notice', array($this, 'doCloseNotice'));
|
||||
|
||||
// Notice styling
|
||||
add_action('admin_head', array($this, 'noticeStyles'));
|
||||
|
||||
// Code related to the AJAX calls and closing the notice
|
||||
add_action('admin_footer', array($this, 'noticeScripts'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function ratePluginNoticeOutput()
|
||||
{
|
||||
// Criteria for showing up the review plugin notice
|
||||
if ( ! $this->showReviewNotice() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show notice and delete the current status (if any)
|
||||
delete_option(WPACU_PLUGIN_ID .'_review_notice_status');
|
||||
|
||||
$goBackToCurrentUrl = '&_wp_http_referer=' . urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) );
|
||||
|
||||
$closeNoticeUrl = esc_url(wp_nonce_url(
|
||||
admin_url('admin-post.php?action='.WPACU_PLUGIN_ID.'_close_review_notice&wpacu_close_reason=_wpacu_close_reason_' . $goBackToCurrentUrl),
|
||||
WPACU_PLUGIN_ID . '_close_review_notice'
|
||||
));
|
||||
|
||||
$closeNoticeMaybeLaterUrl = str_replace('_wpacu_close_reason_', 'maybe_later', $closeNoticeUrl);
|
||||
$closeNoticeNeverShowItUrl = str_replace('_wpacu_close_reason_', 'never_show_it', $closeNoticeUrl);
|
||||
?>
|
||||
<div class="notice wpacu-notice-info is-dismissible wpacu-review-plugin-notice">
|
||||
<p><?php _e('Hey, you have been using Asset CleanUp for some time and already unloaded useless CSS/JS which would give your website a higher page speed score and better user experience.',
|
||||
'wp-asset-clean-up'); ?>
|
||||
<br/> <?php _e('Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?',
|
||||
'wp-asset-clean-up'); ?></p>
|
||||
<p><strong><em>~ Gabriel Livan, Lead Developer</em></strong></p>
|
||||
<p>
|
||||
<a href="<?php echo esc_url(Plugin::RATE_URL); ?>"
|
||||
data-wpacu-close-action="never_show_it"
|
||||
class="wpacu-primary-action wpacu-close-review-notice button-primary"
|
||||
target="_blank"><?php esc_html_e('Ok, you deserve it', 'wp-asset-clean-up'); ?> :)</a>
|
||||
|
||||
<a href="<?php echo esc_url($closeNoticeMaybeLaterUrl); ?>"
|
||||
data-wpacu-close-action="maybe_later"
|
||||
class="wpacu-close-review-notice"
|
||||
rel="noopener noreferrer"><?php esc_html_e('Nope, maybe later', 'wp-asset-clean-up'); ?></a>
|
||||
|
||||
<a href="<?php echo esc_url($closeNoticeNeverShowItUrl) ?>"
|
||||
data-wpacu-close-action="never_show_it"
|
||||
class="wpacu-close-review-notice"
|
||||
rel="noopener noreferrer"><?php esc_html_e('Don\'t show this again', 'wp-asset-clean-up'); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
if (! defined('WPACU_ADMIN_REVIEW_NOTICE_SHOWN')) {
|
||||
define('WPACU_ADMIN_REVIEW_NOTICE_SHOWN', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticeStyles()
|
||||
{
|
||||
?>
|
||||
<style <?php echo Misc::getStyleTypeAttribute(); ?>>
|
||||
.wpacu-review-plugin-notice {
|
||||
border-left: 4px solid #008f9c;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticeScripts()
|
||||
{
|
||||
if ( ! $this->showReviewNotice() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
$(document).on('click', '.wpacu-review-plugin-notice .notice-dismiss', function(event) {
|
||||
$('[data-wpacu-close-action="maybe_later"]').trigger('click');
|
||||
});
|
||||
|
||||
$('.wpacu-close-review-notice').on('click', function(e) {
|
||||
$('.wpacu-review-plugin-notice').fadeOut('fast');
|
||||
|
||||
// If the primary action was taken, also perform the AJAX call to close the notice
|
||||
if (! $(this).hasClass('wpacu-primary-action')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
var wpacuXhr = new XMLHttpRequest(),
|
||||
wpacuCloseAction = $(this).attr('data-wpacu-close-action');
|
||||
|
||||
wpacuXhr.open('POST', '<?php echo esc_url(admin_url('admin-ajax.php')); ?>');
|
||||
wpacuXhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
wpacuXhr.onload = function () {
|
||||
if (wpacuXhr.status === 200) {
|
||||
} else if (wpacuXhr.status !== 200) {
|
||||
}
|
||||
};
|
||||
|
||||
wpacuXhr.send(encodeURI('action=<?php echo WPACU_PLUGIN_ID . '_close_review_notice'; ?>&wpacu_close_reason=' + wpacuCloseAction));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function ajaxCloseReviewNoticeCallback()
|
||||
{
|
||||
$action = isset($_POST['action']) ? $_POST['action'] : false;
|
||||
|
||||
if ($action !== WPACU_PLUGIN_ID . '_close_review_notice' || ! $action) {
|
||||
exit('Invalid Action');
|
||||
}
|
||||
|
||||
$closeReason = isset($_POST['wpacu_close_reason']) && in_array($_POST['wpacu_close_reason'], self::$closingReasons) ? $_POST['wpacu_close_reason'] : false;
|
||||
|
||||
if (! $closeReason) {
|
||||
exit('Invalid Reason');
|
||||
}
|
||||
|
||||
$this->doCloseNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditions for showing the notice (all should be met):
|
||||
* 1) Used the plugin at least for a week (or a few days if at least 30 assets were unloaded)
|
||||
* 2) At least 10 assets unloaded
|
||||
* 3) The WIKI was read or one of the minify/combine options were enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function showReviewNotice()
|
||||
{
|
||||
if ($this->showReviewNotice !== null) {
|
||||
return $this->showReviewNotice; // already set
|
||||
}
|
||||
|
||||
// On URL request (for debugging)
|
||||
if ( isset($_GET['wpacu_show_review_notice']) ) {
|
||||
$this->showReviewNotice = true;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
// If another Asset CleanUp notice (e.g. for plugin tracking) is already shown
|
||||
// don't also show this one below/above it
|
||||
if (defined('WPACU_ADMIN_TRACKING_NOTICE_SHOWN')) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
$doNotTriggerOnScreens = array(
|
||||
'options-general', 'tools', 'users', 'user', 'profile', 'plugins', 'plugin-editor', 'plugin-install'
|
||||
);
|
||||
|
||||
if (isset($screen->base) && in_array($screen->base, $doNotTriggerOnScreens)) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
$settings = new Settings();
|
||||
$allSettings = $settings->getAll();
|
||||
|
||||
$conditionOneToShow = ( $allSettings['wiki_read'] == 1
|
||||
|| $allSettings['minify_loaded_css'] == 1 || $allSettings['combine_loaded_css'] == 1
|
||||
|| $allSettings['minify_loaded_js'] == 1 || $allSettings['combine_loaded_js'] == 1 );
|
||||
|
||||
if ( ! $conditionOneToShow ) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
$noticeStatus = get_option(WPACU_PLUGIN_ID .'_review_notice_status');
|
||||
|
||||
if (isset($noticeStatus['status']) && $noticeStatus['status'] === 'never_show_it') {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice; // Never show it (user has chosen or the primary button was clicked)
|
||||
}
|
||||
|
||||
if (isset($noticeStatus['status'], $noticeStatus['updated_at']) && $noticeStatus['status'] === 'maybe_later') {
|
||||
// Two weeks after the review notice is closed to show up later
|
||||
$showNoticeAfterTimestamp = ($noticeStatus['updated_at'] + (DAY_IN_SECONDS * 14));
|
||||
|
||||
// If two weeks haven't passed since the user has chosen "Nope, maybe later" then do not show the notice yet
|
||||
if (time() < $showNoticeAfterTimestamp) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that at least {$daysPassedAfterFirstUsage} days has passed after the first usage of the plugin was recorded
|
||||
$firstUsageTimestamp = get_option(WPACU_PLUGIN_ID.'_first_usage');
|
||||
|
||||
if (! $firstUsageTimestamp) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
$unloadedTotalAssets = Misc::getTotalUnloadedAssets();
|
||||
|
||||
// Show the notice after one week
|
||||
$daysPassedAfterFirstUsage = 7;
|
||||
|
||||
// Unloaded at least thirty assets? Show the notice sooner
|
||||
if ($unloadedTotalAssets >= 30) {
|
||||
$daysPassedAfterFirstUsage = 4;
|
||||
}
|
||||
|
||||
if ( (time() - $firstUsageTimestamp) < ($daysPassedAfterFirstUsage * DAY_IN_SECONDS) ) {
|
||||
$this->showReviewNotice = false;
|
||||
return $this->showReviewNotice;
|
||||
}
|
||||
|
||||
$toReturn = ( $unloadedTotalAssets >= 10 ); // finally, there have to be at least 10 unloaded assets
|
||||
$this->showReviewNotice = $toReturn;
|
||||
|
||||
return $toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Either via page reload or AJAX call
|
||||
*/
|
||||
public function doCloseNotice()
|
||||
{
|
||||
$doRedirect = isset($_GET['wpacu_close_reason']) && ! defined('DOING_AJAX');
|
||||
$reason = isset($_REQUEST['wpacu_close_reason']) && in_array($_REQUEST['wpacu_close_reason'], self::$closingReasons) ? sanitize_text_field($_REQUEST['wpacu_close_reason']) : false;
|
||||
|
||||
if (! $reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
$performUpdate = false;
|
||||
|
||||
if ($reason === 'never_show_it') {
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_review_notice_status', array('status' => 'never_show_it'));
|
||||
$performUpdate = true;
|
||||
} elseif ($reason === 'maybe_later') {
|
||||
// Set the current timestamp and show it later (e.g. in 2 weeks from now)
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_review_notice_status', array('status' => 'maybe_later', 'updated_at' => time()));
|
||||
$performUpdate = true;
|
||||
}
|
||||
|
||||
// AJAX call return
|
||||
if ($performUpdate && $doRedirect === false) {
|
||||
echo 'success';
|
||||
exit();
|
||||
}
|
||||
|
||||
// The AJAX call should be successful
|
||||
// This redirect is made as a fallback in case the page is reloaded
|
||||
if ( $doRedirect && wp_get_referer() ) {
|
||||
wp_safe_redirect( wp_get_referer() );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
586
wp-content/plugins/wp-asset-clean-up/classes/PluginTracking.php
Normal file
586
wp-content/plugins/wp-asset-clean-up/classes/PluginTracking.php
Normal file
@ -0,0 +1,586 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class PluginTracking
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class PluginTracking
|
||||
{
|
||||
/**
|
||||
* The data to send to the Asset CleanUp site
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Initiate Settings Class
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
public $settings;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $showTrackingNotice = false;
|
||||
|
||||
/**
|
||||
* PluginTracking constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->settings = new Settings();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
// Schedule
|
||||
add_action('wp', array($this, 'scheduleEvents' ));
|
||||
add_action('init', array($this, 'scheduleSend' ));
|
||||
|
||||
// Triggers when Buttons from the Top Notice are clicked and page is reloaded (non-AJAX call)
|
||||
// This is a fallback in case there are JS errors and the AJAX call is not triggering
|
||||
if (isset($_GET['wpacu_is_page_reload']) && $_GET['wpacu_is_page_reload']) {
|
||||
add_action('admin_init', array($this, 'optInOut' ));
|
||||
}
|
||||
|
||||
// Before "Settings" are saved in the database, right after form submit
|
||||
// Check "Allow Usage Tracking" value and take action if it's enabled
|
||||
add_action('wpacu_before_save_settings', array($this, 'checkForSettingsOptIn' ));
|
||||
|
||||
// Notice on the top screen within the Dashboard to get permission from the user to allow tracking
|
||||
add_action('admin_notices', array($this, 'adminNotice'));
|
||||
|
||||
add_action('admin_head', array($this, 'noticeStyles' ));
|
||||
add_action('admin_footer', array($this, 'noticeScripts' ));
|
||||
|
||||
// Close the notice when action is taken by AJAX call
|
||||
add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_close_tracking_notice', array($this, 'ajaxCloseTrackingNoticeCallback'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isAjaxCall
|
||||
* @return bool|string|void
|
||||
*/
|
||||
public function optInOut($isAjaxCall = false)
|
||||
{
|
||||
if ( ! isset($_REQUEST['wpacu_action']) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = '';
|
||||
$redirect = true;
|
||||
|
||||
if ($isAjaxCall) {
|
||||
$redirect = false;
|
||||
}
|
||||
|
||||
$wpacuAction = isset($_REQUEST['wpacu_action']) ? $_REQUEST['wpacu_action'] : '';
|
||||
|
||||
if ($wpacuAction === 'wpacu_opt_into_tracking') {
|
||||
$response = $this->checkForOptIn();
|
||||
}
|
||||
|
||||
if ($wpacuAction === 'wpacu_opt_out_of_tracking') {
|
||||
$response = $this->checkForOptOut();
|
||||
|
||||
if ($redirect) {
|
||||
// Reload the same page without the Asset CleanUp query action
|
||||
wp_redirect(remove_query_arg(array('wpacu_action', 'wpacu_is_page_reload')));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger scheduling
|
||||
*/
|
||||
public function scheduleEvents()
|
||||
{
|
||||
$this->weeklyEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule weekly events
|
||||
*
|
||||
* @access private
|
||||
* @since 1.6
|
||||
* @return void
|
||||
*/
|
||||
private function weeklyEvents()
|
||||
{
|
||||
if (! wp_next_scheduled('wpacu_weekly_scheduled_events')) {
|
||||
wp_schedule_event(current_time('timestamp', true), 'weekly', 'wpacu_weekly_scheduled_events');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user has opted into tracking
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function trackingAllowed()
|
||||
{
|
||||
$allowUsageTracking = $this->settings->getOption('allow_usage_tracking');
|
||||
return (bool) $allowUsageTracking;
|
||||
}
|
||||
/**
|
||||
* Set up the data that is going to be tracked
|
||||
*
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
public function setupData()
|
||||
{
|
||||
$data = array();
|
||||
|
||||
// Retrieve current theme info
|
||||
$themeData = wp_get_theme();
|
||||
$theme = $themeData->get('Name') . ' ' . $themeData->get('Version');
|
||||
|
||||
$settingsClass = new Settings();
|
||||
|
||||
$data['php_version'] = PHP_VERSION;
|
||||
$data['wpacu_version'] = WPACU_PLUGIN_VERSION;
|
||||
$data['wpacu_settings'] = $settingsClass->getAll();
|
||||
$data['wpacu_first_usage'] = get_option(WPACU_PLUGIN_ID.'_first_usage');
|
||||
$data['wpacu_review_info'] = get_option(WPACU_PLUGIN_ID.'_review_notice_status');
|
||||
$data['wp_version'] = get_bloginfo('version');
|
||||
$data['server'] = isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '';
|
||||
$data['multisite'] = is_multisite() ? 'Yes' : 'No';
|
||||
$data['theme'] = $theme;
|
||||
|
||||
// Retrieve current plugin information
|
||||
$adminPluginFile = ABSPATH . '/wp-admin/includes/plugin.php';
|
||||
if (! function_exists( 'get_plugins') && is_file($adminPluginFile)) {
|
||||
include $adminPluginFile;
|
||||
}
|
||||
|
||||
$plugins = array_keys(get_plugins());
|
||||
$active_plugins = Misc::getActivePlugins();
|
||||
|
||||
foreach ($plugins as $key => $plugin) {
|
||||
if (in_array($plugin, $active_plugins)) {
|
||||
// Remove active plugins from list, so we can show active and inactive separately
|
||||
unset($plugins[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$data['active_plugins'] = $active_plugins;
|
||||
$data['inactive_plugins'] = $plugins;
|
||||
$data['locale'] = get_locale();
|
||||
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the data to the Asset CleanUp server
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param bool $override If we should override the tracking setting.
|
||||
* @param bool $ignoreLastCheckIn If we should ignore when the last check in was.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sendCheckIn($override = false, $ignoreLastCheckIn = false)
|
||||
{
|
||||
// Allows us to stop the plugin's own site from checking in, and a filter for any related sites
|
||||
if (apply_filters('wpacu_disable_tracking_checkin', false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $override && ! $this->trackingAllowed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a maximum of once per week
|
||||
$lastSend = $this->getLastSend();
|
||||
|
||||
if ( ! $ignoreLastCheckIn && is_numeric($lastSend) && $lastSend > strtotime('-1 week')) {
|
||||
return 'Not Sent: Only Weekly';
|
||||
}
|
||||
|
||||
$this->setupData();
|
||||
|
||||
$response = wp_remote_post('https://www.assetcleanup.com/tracking/?wpacu_action=checkin', array(
|
||||
'method' => 'POST',
|
||||
'timeout' => 8,
|
||||
'redirection' => 5,
|
||||
'httpversion' => '1.1',
|
||||
'blocking' => false,
|
||||
'body' => $this->data,
|
||||
'user-agent' => 'WPACU/' . WPACU_PLUGIN_VERSION . '; ' . get_bloginfo('url')
|
||||
));
|
||||
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID.'_tracking_last_send', time());
|
||||
|
||||
return wp_remote_retrieve_body($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $savedSettings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function checkForSettingsOptIn($savedSettings)
|
||||
{
|
||||
// Send an initial check in when "Settings" are saved
|
||||
if (isset($savedSettings['allow_usage_tracking']) && $savedSettings['allow_usage_tracking'] == 1) {
|
||||
$this->sendCheckIn( true );
|
||||
}
|
||||
|
||||
return $savedSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a new opt-in via the admin notice or after "Settings" is saved
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function checkForOptIn()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the value in the "Settings" area
|
||||
$this->settings->updateOption('allow_usage_tracking', 1);
|
||||
|
||||
// Send the tracking data
|
||||
$response = $this->sendCheckIn(true);
|
||||
|
||||
// Mark the notice to be hidden
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_hide_tracking_notice', 1);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function checkForOptOut()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return 'Unauthorized';
|
||||
}
|
||||
|
||||
// Disable tracking option from "Settings" and mark the notice as hidden (to not show again)
|
||||
$this->settings->deleteOption('allow_usage_tracking');
|
||||
Misc::addUpdateOption(WPACU_PLUGIN_ID . '_hide_tracking_notice', 1);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last time a checkin was sent
|
||||
*
|
||||
* @access private
|
||||
* @return false|string
|
||||
*/
|
||||
private function getLastSend()
|
||||
{
|
||||
return get_option(WPACU_PLUGIN_ID . '_tracking_last_send');
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a weekly checkin
|
||||
*
|
||||
* We send once a week (while tracking is allowed) to check in, which can be
|
||||
* used to determine active sites.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function scheduleSend()
|
||||
{
|
||||
if (Misc::doingCron()) {
|
||||
add_action('wpacu_weekly_scheduled_events', array($this, 'sendCheckIn' ));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false for showing the top tracking notice
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function showTrackingNotice()
|
||||
{
|
||||
// On URL request (for debugging)
|
||||
if ( isset($_GET['wpacu_show_tracking_notice']) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If another Asset CleanUp notice (e.g. for plugin review) is already shown
|
||||
// don't also show this one below/above it
|
||||
if (defined('WPACU_ADMIN_REVIEW_NOTICE_SHOWN')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->settings->getOption('allow_usage_tracking')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_option(WPACU_PLUGIN_ID . '_hide_tracking_notice')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false !== stripos(network_site_url('/'), 'dev') ||
|
||||
false !== stripos(network_site_url('/'), 'localhost') ||
|
||||
false !== strpos(network_site_url('/'), ':8888') // This is common with MAMP on OS X
|
||||
) {
|
||||
update_option(WPACU_PLUGIN_ID . '_tracking_notice', '1');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function ajaxCloseTrackingNoticeCallback()
|
||||
{
|
||||
check_ajax_referer('wpacu_plugin_tracking_nonce', 'wpacu_security');
|
||||
|
||||
$action = isset($_POST['action']) ? $_POST['action'] : false;
|
||||
|
||||
if ($action !== WPACU_PLUGIN_ID . '_close_tracking_notice' || ! $action) {
|
||||
exit('Invalid Action');
|
||||
}
|
||||
|
||||
$wpacuAction = isset($_POST['wpacu_action']) ? $_POST['wpacu_action'] : false;
|
||||
|
||||
if (! $wpacuAction) {
|
||||
exit('Invalid Asset CleanUp Action');
|
||||
}
|
||||
|
||||
// Allow to Disallow (depending on the action chosen)
|
||||
$response = $this->optInOut(true);
|
||||
echo esc_html($response);
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticeStyles()
|
||||
{
|
||||
?>
|
||||
<style <?php echo Misc::getStyleTypeAttribute(); ?>>
|
||||
.wpacu-tracking-notice {
|
||||
border-left-color: #008f9c;
|
||||
}
|
||||
|
||||
.wpacu-tracking-notice .wpacu-action-links {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.wpacu-tracking-notice .wpacu-action-links ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wpacu-tracking-notice .wpacu-action-links ul li.wpacu-optin {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.wpacu-tracking-notice .wpacu-action-links ul li.wpacu-optout {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.wpacu-tracking-notice .wpacu-action-links ul li.wpacu-more-info {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#wpacu-tracked-data-list {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
#wpacu-tracked-data-list .table-striped {
|
||||
border: none;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
#wpacu-tracked-data-list .wpacu_table_wrap .table.table-striped th,
|
||||
#wpacu-tracked-data-list .wpacu_table_wrap .table.table-striped td {
|
||||
padding: 0.62rem;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #eceeef;
|
||||
}
|
||||
|
||||
#wpacu-tracked-data-list .table-striped tbody tr:nth-of-type(even) {
|
||||
background-color: rgba(0, 143, 156, 0.05);
|
||||
}
|
||||
|
||||
#wpacu-tracked-data-list .table-striped tbody tr td:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticeScripts()
|
||||
{
|
||||
if (! $this->showTrackingNotice) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
var $wpacuTrackedDataList = $('#wpacu-tracked-data-list');
|
||||
|
||||
// Tracking Info Link Clicked
|
||||
$('#wpacu-show-tracked-data').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if ($wpacuTrackedDataList.is(':hidden')) {
|
||||
$wpacuTrackedDataList.slideDown('fast');
|
||||
} else {
|
||||
$wpacuTrackedDataList.slideUp('fast');
|
||||
}
|
||||
});
|
||||
|
||||
// 'x' click from the top right of the notice
|
||||
$(document).on('click', '.wpacu-tracking-notice .notice-dismiss', function(event) {
|
||||
$('[data-wpacu-close-action="wpacu_opt_out_of_tracking"]').trigger('click');
|
||||
});
|
||||
|
||||
// button click
|
||||
$('.wpacu-close-tracking-notice').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('.wpacu-tracking-notice').fadeOut('fast');
|
||||
|
||||
var wpacuXhr = new XMLHttpRequest(),
|
||||
wpacuCloseAction = $(this).attr('data-wpacu-close-action'),
|
||||
wpacuSecurityNonce = '<?php echo wp_create_nonce('wpacu_plugin_tracking_nonce'); ?>';
|
||||
|
||||
wpacuXhr.open('POST', '<?php echo esc_url(admin_url('admin-ajax.php')); ?>');
|
||||
wpacuXhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
wpacuXhr.onload = function () {
|
||||
if (wpacuXhr.status === 200) {
|
||||
} else if (wpacuXhr.status !== 200) {
|
||||
}
|
||||
};
|
||||
|
||||
wpacuXhr.send(encodeURI('action=<?php echo WPACU_PLUGIN_ID . '_close_tracking_notice'; ?>&wpacu_action=' + wpacuCloseAction + '&wpacu_security='+ wpacuSecurityNonce));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the admin notice to users that have not opted-in or out
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function adminNotice()
|
||||
{
|
||||
if (! $this->showTrackingNotice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setupData();
|
||||
|
||||
$optin_url = add_query_arg(array('wpacu_action' => 'wpacu_opt_into_tracking', 'wpacu_is_page_reload' => true));
|
||||
$optout_url = add_query_arg(array('wpacu_action' => 'wpacu_opt_out_of_tracking', 'wpacu_is_page_reload' => true));
|
||||
|
||||
?>
|
||||
<div class="wpacu-tracking-notice notice is-dismissible">
|
||||
<p><?php _e('Allow Asset CleanUp to anonymously track plugin usage in order to help us make the plugin better? No sensitive or personal data is collected.', 'wp-asset-clean-up'); ?></p>
|
||||
<div class="wpacu-action-links">
|
||||
<ul>
|
||||
<li class="wpacu-optin">
|
||||
<a href="<?php echo esc_url($optin_url); ?>"
|
||||
data-wpacu-close-action="wpacu_opt_into_tracking"
|
||||
class="wpacu-close-tracking-notice button-primary"><?php _e('Allow, I\'m happy to help', 'easy-digital-downloads'); ?></a>
|
||||
</li>
|
||||
<li class="wpacu-optout">
|
||||
<a href="<?php echo esc_url($optout_url); ?>"
|
||||
data-wpacu-close-action="wpacu_opt_out_of_tracking"
|
||||
class="wpacu-close-tracking-notice button-secondary"><?php _e('No, do not allow', 'easy-digital-downloads'); ?></a></li>
|
||||
<li class="wpacu-more-info"><span style="color: #004567;" class="dashicons dashicons-info"></span> <a id="wpacu-show-tracked-data" href="#">What kind of data will be sent for the tracking?</a></li>
|
||||
</ul>
|
||||
<div style="clear: both;"></div>
|
||||
<div style="display: none;" id="wpacu-tracked-data-list">
|
||||
<?php self::showSentInfoDataTable($this->data); ?>
|
||||
</div>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> This option can always be turned ON & OFF in <a style="text-decoration: none;" target="_blank" href="<?php echo admin_url('admin.php?page=wpassetcleanup_settings&wpacu_selected_tab_area=wpacu-setting-plugin-usage-settings#wpacu-settings-allow-usage-tracking'); ?>">"Settings" → "Plugin Usage Preferences" → "Allow Usage Tracking"</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (! defined('WPACU_ADMIN_TRACKING_NOTICE_SHOWN')) {
|
||||
define('WPACU_ADMIN_TRACKING_NOTICE_SHOWN', true);
|
||||
}
|
||||
|
||||
// Only mark it as shown after it was printed
|
||||
$this->showTrackingNotice = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*/
|
||||
public static function showSentInfoDataTable($data)
|
||||
{
|
||||
?>
|
||||
<div class="wpacu_table_wrap">
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<td style="width: 182px;">PHP Version:</td>
|
||||
<td><?php echo esc_html($data['php_version']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Asset CleanUp Info:</td>
|
||||
<td>Version: <?php echo esc_html($data['wpacu_version']); ?>, Settings & Usage Information</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WordPress Version:</td>
|
||||
<td><?php echo esc_html($data['wp_version']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Server:</td>
|
||||
<td><?php echo esc_html($data['server']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multisite:</td>
|
||||
<td><?php echo esc_html($data['multisite']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Theme:</td>
|
||||
<td><?php echo esc_html($data['theme']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Locale:</td>
|
||||
<td><?php echo esc_html($data['locale']); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Plugins:</td>
|
||||
<td>The list of active & inactive plugins</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class PluginsManager
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class PluginsManager
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function page()
|
||||
{
|
||||
// Get active plugins and their basic information
|
||||
$this->data['active_plugins'] = self::getActivePlugins();
|
||||
$this->data['plugins_icons'] = Misc::getAllActivePluginsIcons();
|
||||
|
||||
$wpacuSubPage = (isset($_GET['wpacu_sub_page']) && $_GET['wpacu_sub_page']) ? $_GET['wpacu_sub_page'] : 'manage_plugins_front';
|
||||
$this->data['wpacu_sub_page'] = $wpacuSubPage;
|
||||
|
||||
Main::instance()->parseTemplate('admin-page-plugins-manager', $this->data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getActivePlugins()
|
||||
{
|
||||
$activePluginsFinal = array();
|
||||
|
||||
// Get active plugins and their basic information
|
||||
$activePlugins = wp_get_active_and_valid_plugins();
|
||||
|
||||
// Also check any network activated plugins in case we're dealing with a MultiSite setup
|
||||
if ( is_multisite() ) {
|
||||
$activeNetworkPlugins = wp_get_active_network_plugins();
|
||||
|
||||
if ( ! empty( $activeNetworkPlugins ) ) {
|
||||
foreach ( $activeNetworkPlugins as $activeNetworkPlugin ) {
|
||||
$activePlugins[] = $activeNetworkPlugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$activePlugins = array_unique($activePlugins);
|
||||
|
||||
foreach ($activePlugins as $pluginPath) {
|
||||
// Skip Asset CleanUp as it's obviously needed for the functionality
|
||||
if (strpos($pluginPath, 'wp-asset-clean-up') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$networkActivated = isset($activeNetworkPlugins) && in_array($pluginPath, $activeNetworkPlugins);
|
||||
|
||||
$pluginRelPath = trim(str_replace(WP_PLUGIN_DIR, '', $pluginPath), '/');
|
||||
|
||||
$pluginData = get_plugin_data($pluginPath);
|
||||
|
||||
$activePluginsFinal[] = array(
|
||||
'title' => $pluginData['Name'],
|
||||
'path' => $pluginRelPath,
|
||||
'network_activated' => $networkActivated
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty($activePluginsFinal) ) {
|
||||
usort( $activePluginsFinal, static function( $a, $b ) {
|
||||
return strcmp( $a['title'], $b['title'] );
|
||||
} );
|
||||
}
|
||||
|
||||
return $activePluginsFinal;
|
||||
}
|
||||
}
|
625
wp-content/plugins/wp-asset-clean-up/classes/Preloads.php
Normal file
625
wp-content/plugins/wp-asset-clean-up/classes/Preloads.php
Normal file
@ -0,0 +1,625 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
|
||||
|
||||
/**
|
||||
* Class Preloads
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Preloads
|
||||
{
|
||||
/**
|
||||
* Printed in HEAD
|
||||
*/
|
||||
const DEL_STYLES_PRELOADS = '<meta name="wpacu-generator" content="ASSET CLEANUP STYLES PRELOADS">';
|
||||
|
||||
/**
|
||||
* Printed in HEAD
|
||||
*/
|
||||
const DEL_SCRIPTS_PRELOADS = '<meta name="wpacu-generator" content="ASSET CLEANUP SCRIPTS PRELOADS">';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $preloads = array('styles' => array(), 'scripts' => array());
|
||||
|
||||
/**
|
||||
* @var Preloads|null
|
||||
*/
|
||||
private static $singleton;
|
||||
|
||||
/**
|
||||
* @return null|Preloads
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (self::$singleton === null) {
|
||||
self::$singleton = new self();
|
||||
}
|
||||
|
||||
return self::$singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (is_admin() || self::preventPreload()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->preloads = $this->getPreloads();
|
||||
|
||||
add_filter('wpfc_buffer_callback_filter', static function ($buffer) {
|
||||
$buffer = str_replace('rel=\'preload\' data-from-rel=\'stylesheet\'', 'rel=\'preload\'', $buffer);
|
||||
return $buffer;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! is_admin()) { // Trigger only in the front-end
|
||||
add_filter('style_loader_tag', array($this, 'preloadCss'), 10, 2);
|
||||
add_filter('script_loader_tag', array($this, 'preloadJs'), 10, 2);
|
||||
} else { // Trigger only within the Dashboard
|
||||
if (Misc::getVar('post', 'wpacu_remove_preloaded_assets_nonce')) {
|
||||
add_action('admin_init', static function() {
|
||||
Preloads::removePreloadFromChosenAssets();
|
||||
});
|
||||
}
|
||||
|
||||
// Trigger only in "Bulk Changes" -> "Preloaded CSS/JS"
|
||||
if (isset($_GET['page']) && $_GET['page'] === WPACU_PLUGIN_ID.'_bulk_unloads'
|
||||
&& get_transient('wpacu_preloads_just_removed')) {
|
||||
add_action('wpacu_admin_notices', array($this, 'noticePreloadsRemoved'));
|
||||
delete_transient('wpacu_preloads_just_removed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function doChanges($htmlSource)
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$this->preloads = $this->getPreloads();
|
||||
|
||||
if (isset($this->preloads['styles']) && ! empty($this->preloads['styles'])) {
|
||||
$htmlSource = self::appendPreloadsForStylesToHead($htmlSource);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $for
|
||||
* @return bool
|
||||
*/
|
||||
public function enablePreloads($for)
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$assetType = ($for === 'css') ? 'styles' : 'scripts';
|
||||
|
||||
if (! (isset($this->preloads[$assetType]) && ! empty($this->preloads[$assetType]))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not use the preloads if "Optimize CSS Delivery" is enabled in WP Rocket
|
||||
if ($for === 'css' && Misc::isPluginActive('wp-rocket/wp-rocket.php') && function_exists('get_rocket_option') && get_rocket_option('async_css')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// WP Fastest Cache: Combine CSS/JS is enabled
|
||||
if (! Menu::userCanManageAssets() && Misc::isPluginActive('wp-fastest-cache/wpFastestCache.php')) {
|
||||
$wpfcOptionsJson = get_option('WpFastestCache');
|
||||
$wpfcOptions = @json_decode($wpfcOptionsJson, ARRAY_A);
|
||||
|
||||
if ($for === 'css' && isset($wpfcOptions['wpFastestCacheCombineCss'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($for === 'js' && isset($wpfcOptions['wpFastestCacheCombineJs'])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// W3 Total Cache
|
||||
if (Misc::isPluginActive('w3-total-cache/w3-total-cache.php')) {
|
||||
$w3tcConfigMaster = Misc::getW3tcMasterConfig();
|
||||
|
||||
if ($for === 'css') {
|
||||
$w3tcEnableCss = (int)trim(Misc::extractBetween($w3tcConfigMaster, '"minify.css.enable":', ','), '" ');
|
||||
|
||||
if ($w3tcEnableCss === 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($for === 'js') {
|
||||
$w3tcEnableJs = (int)trim(Misc::extractBetween($w3tcConfigMaster, '"minify.js.enable":', ','), '" ');
|
||||
|
||||
if ($w3tcEnableJs === 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LiteSpeed Cache
|
||||
if (Misc::isPluginActive('litespeed-cache/litespeed-cache.php') && ($liteSpeedCacheConf = apply_filters('litespeed_cache_get_options', get_option('litespeed-cache-conf')))) {
|
||||
if ($for === 'css' && isset($liteSpeedCacheConf['css_minify']) && $liteSpeedCacheConf['css_minify']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($for === 'js' && isset($liteSpeedCacheConf['js_minify']) && $liteSpeedCacheConf['js_minify']) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getPreloads()
|
||||
{
|
||||
$preloadsListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
|
||||
|
||||
if ($preloadsListJson) {
|
||||
$preloadsList = @json_decode($preloadsListJson, true);
|
||||
|
||||
// Issues with decoding the JSON file? Return an empty list
|
||||
if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
|
||||
return $this->preloads;
|
||||
}
|
||||
|
||||
// Are new positions set for styles and scripts?
|
||||
foreach (array('styles', 'scripts') as $assetKey) {
|
||||
if ( isset( $preloadsList[$assetKey]['preloads'] ) && ! empty( $preloadsList[$assetKey]['preloads'] ) ) {
|
||||
$this->preloads[$assetKey] = $preloadsList[$assetKey]['preloads'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->preloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlTag
|
||||
* @param $handle
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function preloadCss($htmlTag, $handle)
|
||||
{
|
||||
if (Plugin::preventAnyFrontendOptimization() || self::preventPreload()) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if ($wpacuAsyncPreloadHandle = Misc::getVar('get', 'wpacu_preload_css')) {
|
||||
// For testing purposes: Check how the page loads with the requested CSS preloaded
|
||||
$this->preloads['styles'][$wpacuAsyncPreloadHandle] = 'basic';
|
||||
}
|
||||
|
||||
// Only valid for front-end pages with LINKs
|
||||
if (is_admin() || (! $this->enablePreloads('css')) || strpos($htmlTag,'<link ') === false || Main::instance()->preventAssetsSettings()) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if (! isset($this->preloads['styles'])) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if (array_key_exists($handle, $this->preloads['styles']) && $this->preloads['styles'][$handle]) {
|
||||
if (isset($_REQUEST['wpacu_no_css_preload_basic'])) { // do not apply it for debugging purposes
|
||||
return str_replace('<link ', '<link data-wpacu-skip-preload=\'1\' ', $htmlTag);
|
||||
}
|
||||
|
||||
ObjectCache::wpacu_cache_set($handle, 1, 'wpacu_basic_preload_handles');
|
||||
return str_replace('<link ', '<link data-wpacu-to-be-preloaded-basic=\'1\' ', $htmlTag);
|
||||
}
|
||||
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlTag
|
||||
* @param $handle
|
||||
* @return string
|
||||
*/
|
||||
public function preloadJs($htmlTag, $handle)
|
||||
{
|
||||
if (Plugin::preventAnyFrontendOptimization() || self::preventPreload()) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['wpacu_no_js_preload_basic'])) {
|
||||
return str_replace('<script ', '<script data-wpacu-skip-preload=\'1\' ', $htmlTag);
|
||||
}
|
||||
|
||||
// For testing purposes: Check how the page loads with the requested JS preloaded
|
||||
if ($wpacuJsPreloadHandle = Misc::getVar('get', 'wpacu_preload_js')) {
|
||||
$this->preloads['scripts'][$wpacuJsPreloadHandle] = 1;
|
||||
}
|
||||
|
||||
// Only valid for front-end pages with SCRIPTs
|
||||
if (is_admin() || (! $this->enablePreloads('js')) || strpos($htmlTag,'<script ') === false || Main::instance()->preventAssetsSettings()) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if (! isset($this->preloads['scripts'])) {
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
if (array_key_exists($handle, $this->preloads['scripts']) && $this->preloads['scripts'][$handle]) {
|
||||
return str_replace('<script ', '<script data-wpacu-to-be-preloaded-basic=\'1\' ', $htmlTag);
|
||||
}
|
||||
|
||||
return $htmlTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function appendPreloadsForStylesToHead($htmlSource)
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
// Perhaps it's not applicable in the current page (no LINK tags are loaded that should be preloaded)
|
||||
if (strpos($htmlSource, 'data-wpacu-to-be-preloaded-basic') === false) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$allHrefs = array();
|
||||
$stickToRegEx = true; // default
|
||||
|
||||
// Something might not be right with the RegEx; Fallback to DOMDocument, more accurate, but slower
|
||||
if ( Misc::isDOMDocumentOn() ) {
|
||||
$documentForCSS = Misc::initDOMDocument();
|
||||
|
||||
$htmlSourceAlt = preg_replace( '@<(noscript|style|script)[^>]*?>.*?</\\1>@si', '', $htmlSource );
|
||||
$documentForCSS->loadHTML($htmlSourceAlt);
|
||||
|
||||
$linkTags = $documentForCSS->getElementsByTagName( 'link' );
|
||||
|
||||
if ( count($linkTags) > 0 ) {
|
||||
$matchesSourcesFromLinkTags = array(); // reset its value; new fetch method was used
|
||||
|
||||
foreach ( $linkTags as $tagObject ) {
|
||||
if ( empty( $tagObject->attributes ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$linkAttributes = array();
|
||||
|
||||
foreach ( $tagObject->attributes as $attrObj ) {
|
||||
$linkAttributes[ $attrObj->nodeName ] = trim( $attrObj->nodeValue );
|
||||
}
|
||||
|
||||
if ( ! isset( $linkAttributes['data-wpacu-to-be-preloaded-basic'], $linkAttributes['href'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($htmlSourceAlt, $linkAttributes['href']) === false) {
|
||||
$stickToRegEx = true; // the source value is not the same as in the HTML source (e.g. altered by the DOM) / fallback to RegEx
|
||||
break;
|
||||
}
|
||||
|
||||
$linkTag = Misc::getOuterHTML( $tagObject );
|
||||
|
||||
$allHrefs[$linkTag] = $linkAttributes['href'];
|
||||
}
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
}
|
||||
|
||||
if ($stickToRegEx) {
|
||||
// Use the RegEx as it's much faster and very accurate in this situation
|
||||
$strContainsFormat = preg_quote('data-wpacu-to-be-preloaded-basic', '/');
|
||||
preg_match_all('#<link[^>]*'.$strContainsFormat.'[^>]*' . '\shref(\s+|)=(\s+|)(\'|"|)(.*)(\\3)' . '.*(>)#Usmi', $htmlSource, $matchesSourcesFromLinkTags, PREG_SET_ORDER);
|
||||
|
||||
if ( ! empty($matchesSourcesFromLinkTags) ) {
|
||||
foreach ( $matchesSourcesFromLinkTags as $linkTagArray ) {
|
||||
$linkTag = isset( $linkTagArray[0] ) ? $linkTagArray[0] : false;
|
||||
|
||||
if ($linkTag) {
|
||||
$linkHref = isset( $linkTagArray[0] ) ? Misc::getValueFromTag( $linkTag ) : false;
|
||||
|
||||
if ( $linkHref ) {
|
||||
$allHrefs[$linkTag] = $linkHref;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allHrefs = array_unique($allHrefs);
|
||||
|
||||
if ( ! empty($allHrefs) ) {
|
||||
foreach ( $allHrefs as $linkTag => $linkHref ) {
|
||||
$condBefore = $condAfter = '';
|
||||
|
||||
// Any IE comments around the tag?
|
||||
$scriptIdAttr = Misc::getValueFromTag($linkTag, 'id');
|
||||
|
||||
if ($scriptIdAttr && substr( $scriptIdAttr, -4 ) === '-css') {
|
||||
$linkHandle = substr( $scriptIdAttr, 0, -4 );
|
||||
|
||||
$linkObj = isset(Main::instance()->wpAllStyles['registered'][$linkHandle]) ? Main::instance()->wpAllStyles['registered'][$linkHandle] : false;
|
||||
|
||||
if ($linkObj) {
|
||||
$conditional = isset($linkObj->extra['conditional']) ? $linkObj->extra['conditional'] : '';
|
||||
|
||||
if ($conditional) {
|
||||
$condBefore = "<!--[if {$conditional}]>\n";
|
||||
$condAfter = "<![endif]-->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$linkPreload = $condBefore;
|
||||
$linkPreload .= self::linkPreloadCssFormat( $linkHref );
|
||||
$linkPreload .= $condAfter;
|
||||
|
||||
$htmlSource = str_replace( self::DEL_STYLES_PRELOADS, $linkPreload . self::DEL_STYLES_PRELOADS, $htmlSource );
|
||||
}
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $linkHref
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function linkPreloadCssFormat($linkHref)
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return $linkHref;
|
||||
}
|
||||
|
||||
if (OptimizeCss::wpfcMinifyCssEnabledOnly()) {
|
||||
return '<link rel=\'preload\' data-from-rel=\'stylesheet\' as=\'style\' data-href-before=\''.$linkHref.'\' href=\''.esc_attr($linkHref).'\' data-wpacu-preload-css-basic=\'1\' />' . "\n";
|
||||
}
|
||||
|
||||
return '<link rel=\'preload\' as=\'style\' href=\''.esc_attr($linkHref).'\' data-wpacu-preload-css-basic=\'1\' />'."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $htmlSource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function appendPreloadsForScriptsToHead($htmlSource)
|
||||
{
|
||||
if (self::preventPreload()) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
$strContainsFormat = preg_quote('data-wpacu-to-be-preloaded-basic=\'1\'', '/');
|
||||
|
||||
preg_match_all('#<script[^>]*'.$strContainsFormat.'[^>]*' . 'src(\s+|)=(\s+|)(\'|"|)(.*)(\\3)' . '.*(>)#Usmi', $htmlSource, $matchesSourcesFromScriptTags, PREG_SET_ORDER);
|
||||
|
||||
if (empty($matchesSourcesFromScriptTags)) {
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
foreach ($matchesSourcesFromScriptTags as $scriptTagArray) {
|
||||
$scriptTag = isset($scriptTagArray[0]) ? $scriptTagArray[0] : false;
|
||||
|
||||
if (! $scriptTag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scriptSrc = Misc::getValueFromTag($scriptTag);
|
||||
|
||||
$condBefore = $condAfter = '';
|
||||
|
||||
// Any IE comments around the tag?
|
||||
$scriptIdAttr = Misc::getValueFromTag($scriptTag, 'id');
|
||||
|
||||
if ($scriptIdAttr && strpos($scriptTag, '-js') !== false) {
|
||||
$scriptHandle = rtrim($scriptIdAttr, '-js');
|
||||
|
||||
if ($scriptHandle) {
|
||||
$scriptObj = isset(Main::instance()->wpAllScripts['registered'][$scriptHandle]) ? Main::instance()->wpAllScripts['registered'][$scriptHandle] : false;
|
||||
|
||||
if ($scriptObj) {
|
||||
$conditional = isset($scriptObj->extra['conditional']) ? $scriptObj->extra['conditional'] : '';
|
||||
|
||||
if ($conditional) {
|
||||
$condBefore = "<!--[if {$conditional}]>\n";
|
||||
$condAfter = "<![endif]-->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$linkPreload = $condBefore;
|
||||
$linkPreload .= '<link rel=\'preload\' as=\'script\' href=\''.esc_attr($scriptSrc).'\' data-wpacu-preload-js=\'1\'>'."\n";
|
||||
$linkPreload .= $condAfter;
|
||||
|
||||
$htmlSource = str_replace(self::DEL_SCRIPTS_PRELOADS, $linkPreload . self::DEL_SCRIPTS_PRELOADS, $htmlSource);
|
||||
}
|
||||
|
||||
return $htmlSource;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function updatePreloads()
|
||||
{
|
||||
$useGlobalPost = false;
|
||||
|
||||
if ( (isset($_POST[WPACU_FORM_ASSETS_POST_KEY]['styles']) && ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['styles']))
|
||||
|| (isset($_POST[WPACU_FORM_ASSETS_POST_KEY]['scripts']) && ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['scripts'])) ) {
|
||||
$mainVarToUse = self::updatePreloadsAdapt($_POST[WPACU_FORM_ASSETS_POST_KEY]); // New form fields (starting from v1.1.9.9)
|
||||
} elseif (Misc::isValidRequest('post', 'wpacu_preloads')) {
|
||||
$useGlobalPost = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $useGlobalPost && isset($mainVarToUse['wpacu_preloads'])) {
|
||||
$bucketToUse = $mainVarToUse['wpacu_preloads'];
|
||||
} else if (isset($_POST['wpacu_preloads'])) {
|
||||
$bucketToUse = $_POST['wpacu_preloads'];
|
||||
}
|
||||
|
||||
if (! isset($bucketToUse['styles']) && ! isset($bucketToUse['scripts'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
|
||||
$globalKey = 'preloads';
|
||||
|
||||
$existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
|
||||
$existingListJson = get_option($optionToUpdate);
|
||||
|
||||
$existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
|
||||
$existingList = $existingListData['list'];
|
||||
|
||||
foreach (array('styles', 'scripts') as $assetType) {
|
||||
if ( isset( $bucketToUse[$assetType] ) && ! empty( $bucketToUse[$assetType] ) ) {
|
||||
foreach ( $bucketToUse[$assetType] as $assetHandle => $assetPreload ) {
|
||||
$assetPreload = trim( $assetPreload );
|
||||
|
||||
if ( $assetPreload === '' && isset( $existingList[$assetType][ $globalKey ][ $assetHandle ] ) ) {
|
||||
unset( $existingList[$assetType][ $globalKey ][ $assetHandle ] );
|
||||
} elseif ( $assetPreload !== '' ) {
|
||||
$existingList[$assetType][ $globalKey ][ $assetHandle ] = $assetPreload;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $mainFormArray
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function updatePreloadsAdapt($mainFormArray)
|
||||
{
|
||||
$wpacuPreloadsList = array();
|
||||
|
||||
foreach (array('styles', 'scripts') as $assetKey) {
|
||||
if (isset($mainFormArray[$assetKey]) && ! empty($mainFormArray[$assetKey])) {
|
||||
foreach ($mainFormArray[$assetKey] as $assetHandle => $assetData) {
|
||||
$wpacuPreloadsList['wpacu_preloads'][$assetKey][$assetHandle] = ''; // default
|
||||
|
||||
if (isset($assetData['preload']) && $assetData['preload']) {
|
||||
$wpacuPreloadsList['wpacu_preloads'][ $assetKey ][ $assetHandle ] = $assetData['preload']; // 'basic' or 'async'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $wpacuPreloadsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered from "Bulk Unloads" - "Preloaded CSS/JS"
|
||||
* after the selection is made and button is clicked
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function removePreloadFromChosenAssets()
|
||||
{
|
||||
$stylesCheckedList = Misc::getVar('post', 'wpacu_styles_remove_preloads', array());
|
||||
$scriptsCheckedList = Misc::getVar('post', 'wpacu_scripts_remove_preloads', array());
|
||||
|
||||
if (empty($stylesCheckedList) && empty($scriptsCheckedList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
\check_admin_referer('wpacu_remove_preloaded_assets', 'wpacu_remove_preloaded_assets_nonce');
|
||||
|
||||
$optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
|
||||
$globalKey = 'preloads';
|
||||
|
||||
$existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
|
||||
$existingListJson = get_option($optionToUpdate);
|
||||
|
||||
$existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
|
||||
$existingList = $existingListData['list'];
|
||||
|
||||
if (! empty($stylesCheckedList)) {
|
||||
foreach ($stylesCheckedList as $styleHandle => $action) {
|
||||
if ($action === 'remove') {
|
||||
unset($existingList['styles'][$globalKey][$styleHandle]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($scriptsCheckedList)) {
|
||||
foreach ($scriptsCheckedList as $scriptHandle => $action) {
|
||||
if ($action === 'remove') {
|
||||
unset($existingList['scripts'][$globalKey][$scriptHandle]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
|
||||
|
||||
set_transient('wpacu_preloads_just_removed', 1, 30);
|
||||
|
||||
wp_safe_redirect(admin_url('admin.php?page=wpassetcleanup_bulk_unloads&wpacu_bulk_menu_tab=preloaded_assets&wpacu_time='.time()));
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function noticePreloadsRemoved()
|
||||
{
|
||||
?>
|
||||
<div class="updated notice wpacu-notice is-dismissible">
|
||||
<p><span class="dashicons dashicons-yes"></span>
|
||||
<?php
|
||||
_e('The preload option was removed for the chosen CSS/JS.', 'wp-asset-clean-up');
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function preventPreload()
|
||||
{
|
||||
if (defined('WPACU_ALLOW_ONLY_UNLOAD_RULES') && WPACU_ALLOW_ONLY_UNLOAD_RULES) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
1093
wp-content/plugins/wp-asset-clean-up/classes/Settings.php
Normal file
1093
wp-content/plugins/wp-asset-clean-up/classes/Settings.php
Normal file
File diff suppressed because it is too large
Load Diff
283
wp-content/plugins/wp-asset-clean-up/classes/Sorting.php
Normal file
283
wp-content/plugins/wp-asset-clean-up/classes/Sorting.php
Normal file
@ -0,0 +1,283 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class Sorting
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Sorting
|
||||
{
|
||||
/**
|
||||
* Sorts styles or scripts list in alphabetical ascending order (from A to Z) by the handle name
|
||||
*
|
||||
* @param $list
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function sortListByAlpha($list)
|
||||
{
|
||||
if (isset($list['styles']) && ! empty($list['styles'])) {
|
||||
$newStyles = array();
|
||||
|
||||
foreach ($list['styles'] as $indexNo => $styleObj) {
|
||||
if (! isset($styleObj->handle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($assetAlt = self::matchesWpCoreCriteria($styleObj, 'styles')) {
|
||||
if (isset($assetAlt->wp)) {
|
||||
$styleObj->wp = true;
|
||||
}
|
||||
|
||||
if (isset($assetAlt->ver)) {
|
||||
$styleObj->ver = $assetAlt->ver;
|
||||
}
|
||||
}
|
||||
|
||||
$newStyles[$styleObj->handle] = $styleObj;
|
||||
}
|
||||
|
||||
$list['styles'] = $newStyles;
|
||||
|
||||
sort($list['styles']);
|
||||
}
|
||||
|
||||
if (isset($list['scripts']) && ! empty($list['scripts'])) {
|
||||
$newScripts = array();
|
||||
|
||||
foreach ($list['scripts'] as $indexNo => $scriptObj) {
|
||||
if (! isset($scriptObj->handle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($assetAlt = self::matchesWpCoreCriteria($scriptObj, 'scripts')) {
|
||||
if (isset($assetAlt->wp)) {
|
||||
$scriptObj->wp = true;
|
||||
}
|
||||
|
||||
if (isset($assetAlt->ver)) {
|
||||
$scriptObj->ver = $assetAlt->ver;
|
||||
}
|
||||
}
|
||||
|
||||
$newScripts[$scriptObj->handle] = $scriptObj;
|
||||
}
|
||||
|
||||
$list['scripts'] = $newScripts;
|
||||
|
||||
sort($list['scripts']);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* The appended location values will be used to sort the list of assets
|
||||
*
|
||||
* @param $list
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function appendLocation($list)
|
||||
{
|
||||
if (empty($list) || (! isset($list['styles']) && ! isset($list['scripts']))) {
|
||||
return $list;
|
||||
}
|
||||
|
||||
$pluginsUrl = plugins_url();
|
||||
|
||||
$urlsToThemeDirs = array();
|
||||
|
||||
foreach (search_theme_directories() as $themeDir => $themeDirArray) {
|
||||
$themeUrl = '/'.
|
||||
str_replace(
|
||||
'//',
|
||||
'/',
|
||||
str_replace(Misc::getWpRootDirPath(), '', $themeDirArray['theme_root']) . '/'. $themeDir . '/'
|
||||
);
|
||||
|
||||
$urlsToThemeDirs[] = $themeUrl;
|
||||
}
|
||||
|
||||
$urlsToThemeDirs = array_unique($urlsToThemeDirs);
|
||||
|
||||
foreach (array('styles', 'scripts') as $assetType) {
|
||||
if ( ! (isset($list[$assetType]) && ! empty($list[$assetType])) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $list[$assetType] as $indexNo => $asset ) {
|
||||
$src = isset($asset->src) ? $asset->src : '';
|
||||
$miscLocalSrc = Misc::getLocalSrc($src);
|
||||
|
||||
if ($assetAlt = self::matchesWpCoreCriteria($asset, $assetType)) {
|
||||
// Core Files
|
||||
$asset->locationMain = 'wp_core';
|
||||
$asset->locationChild = 'none';
|
||||
|
||||
if (isset($assetAlt->wp)) {
|
||||
$asset->wp = true;
|
||||
}
|
||||
|
||||
if (isset($assetAlt->ver)) {
|
||||
$asset->ver = true;
|
||||
}
|
||||
} elseif ($pluginDir = self::matchesPluginCriteria($asset)) {
|
||||
// From plugins directory (usually /wp-content/plugins/)
|
||||
if ($pluginDir === 'n/a' && $src) {
|
||||
if (strpos($src, '/'.Misc::getPluginsDir().'/') !== false) {
|
||||
$srcParts = explode('/'.Misc::getPluginsDir().'/', $src);
|
||||
list ($pluginDir) = explode('/', $srcParts[1]);
|
||||
} else {
|
||||
$relSrc = str_replace($pluginsUrl, '', $src);
|
||||
|
||||
if ($relSrc[0] === '/') {
|
||||
$relSrc = substr($relSrc, 1);
|
||||
}
|
||||
|
||||
list ($pluginDir) = explode('/', $relSrc);
|
||||
}
|
||||
}
|
||||
|
||||
$asset->locationMain = 'plugins';
|
||||
$asset->locationChild = $pluginDir;
|
||||
|
||||
} elseif ( (! empty($miscLocalSrc) && strpos($src, '/wp-content/uploads/') !== false) || strpos($src, '/wp-content/uploads/') === 0 ) {
|
||||
$asset->locationMain = 'uploads';
|
||||
$asset->locationChild = 'none';
|
||||
} else {
|
||||
$isWithinThemes = false;
|
||||
|
||||
foreach ( $urlsToThemeDirs as $urlToThemeDir ) {
|
||||
$srcRel = str_replace(site_url(),'', $src);
|
||||
|
||||
if ( strpos( $srcRel, $urlToThemeDir ) !== false ) {
|
||||
$isWithinThemes = true;
|
||||
|
||||
$themeDir = substr(strrchr(trim($urlToThemeDir, '/'), '/'), 1);
|
||||
|
||||
$asset->locationMain = 'themes';
|
||||
$asset->locationChild = $themeDir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Default: "External"
|
||||
if ( ! $isWithinThemes ) {
|
||||
// Outside "themes", "plugins" and "wp-includes"
|
||||
$asset->locationMain = 'external';
|
||||
$asset->locationChild = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
$list[$assetType][$indexNo] = $asset;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $asset
|
||||
* @param $assetType
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function matchesWpCoreCriteria($asset, $assetType)
|
||||
{
|
||||
global $wp_version;
|
||||
|
||||
$src = isset($asset->src) ? $asset->src : '';
|
||||
|
||||
$localSrc = Misc::getLocalSrc($asset->src);
|
||||
|
||||
$srcToUse = $src;
|
||||
|
||||
if (! empty($localSrc) && isset($localSrc['rel_src']) && $localSrc['rel_src']) {
|
||||
$srcToUse = $localSrc['rel_src']; // the relative path
|
||||
}
|
||||
|
||||
$isJQueryHandle = ($assetType === 'scripts') && in_array($asset->handle, array('jquery', 'jquery-core', 'jquery-migrate'));
|
||||
$isJQueryUpdater = ($assetType === 'scripts') && strpos($asset->src, '/' . Misc::getPluginsDir( 'dir_name' ) . '/jquery-updater/js/jquery-') !== false;
|
||||
|
||||
$startsWithWpIncludes = strpos($srcToUse,'wp-includes/') === 0;
|
||||
$startsWithWpAdmin = strpos($srcToUse,'wp-admin/') === 0;
|
||||
$wpCoreOnJetpackCdn = strpos($src, '.wp.com/c/'.$wp_version.'/wp-includes/') !== false;
|
||||
|
||||
$coreCssHandlesList = <<<LIST
|
||||
global-styles
|
||||
global-styles-css-custom-properties
|
||||
wp-block-directory
|
||||
wp-block-library
|
||||
wp-block-styles
|
||||
wp-block-library-theme
|
||||
wp-block-pattern
|
||||
wp-webfonts
|
||||
wp-block-post-date
|
||||
LIST;
|
||||
$cssCoreHandles = array_merge(
|
||||
explode("\n", $coreCssHandlesList),
|
||||
Misc::getWpCoreCssHandlesFromWpIncludesBlocks() // Source: /wp-includes/blocks/
|
||||
);
|
||||
|
||||
$coreJsHandlesList = <<<LIST
|
||||
admin-bar
|
||||
code-editor
|
||||
jquery-ui-datepicker
|
||||
LIST;
|
||||
$jsCoreHandles = explode("\n", $coreJsHandlesList);
|
||||
|
||||
$isCssCoreHandleFromWpIncludesBlocks = ($assetType === 'styles') && in_array($asset->handle, $cssCoreHandles);
|
||||
$isJsCoreHandleFromWpIncludesBlocks = ($assetType === 'scripts') && in_array($asset->handle, $jsCoreHandles);
|
||||
|
||||
if ( ! ($isJQueryHandle || $isJQueryUpdater || $startsWithWpIncludes || $startsWithWpAdmin || $isCssCoreHandleFromWpIncludesBlocks || $isJsCoreHandleFromWpIncludesBlocks || $wpCoreOnJetpackCdn) ) {
|
||||
return false; // none of the above conditions matched, thus, this is not a WP core file
|
||||
}
|
||||
|
||||
$assetAlt = $asset;
|
||||
|
||||
if ($wpCoreOnJetpackCdn) {
|
||||
$assetAlt->wp = true;
|
||||
$assetAlt->ver = $wp_version;
|
||||
}
|
||||
|
||||
return $assetAlt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $asset
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function matchesPluginCriteria($asset)
|
||||
{
|
||||
$src = isset($asset->src) ? $asset->src : '';
|
||||
|
||||
$isOxygenBuilderPlugin = strpos( $src, '/wp-content/uploads/oxygen/css/' ) !== false;
|
||||
$isElementorPlugin = strpos( $src, '/wp-content/uploads/elementor/css/' ) !== false;
|
||||
$isWooCommerceInline = $asset->handle === 'woocommerce-inline';
|
||||
$miscLocalSrc = Misc::getLocalSrc($src);
|
||||
|
||||
$isPlugin = $isOxygenBuilderPlugin ||
|
||||
$isElementorPlugin ||
|
||||
$isWooCommerceInline ||
|
||||
strpos( $src, plugins_url() ) !== false ||
|
||||
((! empty($miscLocalSrc) && strpos($src, '/'.Misc::getPluginsDir().'/') !== false) || strpos($src, '/'.Misc::getPluginsDir().'/') === 0);
|
||||
|
||||
if (! $isPlugin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pluginDir = 'n/a'; // default
|
||||
|
||||
if ($isOxygenBuilderPlugin) {
|
||||
$pluginDir = 'oxygen';
|
||||
} elseif ($isElementorPlugin) {
|
||||
$pluginDir = 'elementor';
|
||||
} elseif ($isWooCommerceInline) {
|
||||
$pluginDir = 'woocommerce';
|
||||
}
|
||||
|
||||
return $pluginDir;
|
||||
}
|
||||
}
|
1730
wp-content/plugins/wp-asset-clean-up/classes/ThirdParty/Browser.php
vendored
Normal file
1730
wp-content/plugins/wp-asset-clean-up/classes/ThirdParty/Browser.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
71
wp-content/plugins/wp-asset-clean-up/classes/Tips.php
Normal file
71
wp-content/plugins/wp-asset-clean-up/classes/Tips.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
/**
|
||||
* Class Tips
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Tips
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $list = array('css' => array(), 'js' => array());
|
||||
|
||||
/**
|
||||
* Tips constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// CSS list
|
||||
$this->list['css']['wp-block-library'] = <<<HTML
|
||||
This asset is related to the Gutenberg block editor. If you do not use it (e.g. you have an alternative option such as Divi, Elementor etc.), then it is safe to unload this file.
|
||||
HTML;
|
||||
|
||||
if ($extraWpBlockLibraryTip = self::ceGutenbergCssLibraryBlockTip()) {
|
||||
$this->list['css']['wp-block-library'] .= ' '.$extraWpBlockLibraryTip;
|
||||
}
|
||||
|
||||
$this->list['css']['astra-contact-form-7'] = <<<HTML
|
||||
This asset is related to the "Contact Form 7" plugin. If you do not use it on this page (e.g. only needed on a page such as "Contact"), then you can safely unload it.
|
||||
HTML;
|
||||
$this->list['css']['contact-form-7'] = <<<HTML
|
||||
This CSS file is related to "Contact Form 7" and if you don't load any form on this page (e.g. you use it only on pages such as Contact, Make a booking etc.), then you can safely unload it (e.g. side-wide and make exceptions on the few pages you use it).
|
||||
HTML;
|
||||
|
||||
$this->list['css']['duplicate-post'] = <<<HTML
|
||||
This CSS file is meant to style the "Duplicate Post" plugin's menu within the top admin bar, and it's loading when the user (with the right privileges) is logged-in. It's NOT meant to load for the guests (non-logged-in visitors). You can leave it loaded.
|
||||
HTML;
|
||||
|
||||
$this->list['css']['dashicons'] = <<<HTML
|
||||
To avoid breaking admin bar's styling which relies on the WordPress Dashicons, any unload rule set for this handle will be ignored IF the user is logged-in and the admin bar is showing up.
|
||||
HTML;
|
||||
// JavaScript list
|
||||
$this->list['js']['wp-embed'] = <<<HTML
|
||||
To completely disable oEmbeds, you can use "Disable oEmbed (Embeds) Site-Wide" from plugin's "Settings" -> "Site-Wide Common Unloads". It will also prevent this file from loading in the first place and hide it from this location.
|
||||
HTML;
|
||||
$this->list['js']['wc-cart-fragments'] = <<<HTML
|
||||
This is used to make an AJAX call to retrieve the latest WooCommerce cart information. If there is no mini cart area (e.g. in a sidebar or menu), you can safely unload this file.
|
||||
HTML;
|
||||
|
||||
$this->list['js']['contact-form-7'] = <<<HTML
|
||||
This JavaScript file is related to "Contact Form 7" and if you don't load any form on this page (e.g. you use it only on pages such as Contact, Make a booking etc.), then you can safely unload it (e.g. side-wide and make exceptions on the few pages you use it).
|
||||
HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tip related to "Classic Editor" plugin and some of its active settings
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ceGutenbergCssLibraryBlockTip()
|
||||
{
|
||||
if (Misc::isClassicEditorUsed()) {
|
||||
return <<<HTML
|
||||
You are using "Classic Editor" plugin and the option "Default editor for all users" is set to "Classic Editor" and "Allow users to switch editors" option is set to "No". It is very likely you do not need the Gutenberg CSS Library Block in any page.
|
||||
HTML;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
842
wp-content/plugins/wp-asset-clean-up/classes/Tools.php
Normal file
842
wp-content/plugins/wp-asset-clean-up/classes/Tools.php
Normal file
@ -0,0 +1,842 @@
|
||||
<?php
|
||||
namespace WpAssetCleanUp;
|
||||
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
|
||||
use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
|
||||
use WpAssetCleanUp\ThirdParty\Browser;
|
||||
|
||||
/**
|
||||
* Class Tools
|
||||
* @package WpAssetCleanUp
|
||||
*/
|
||||
class Tools
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $wpacuFor = 'reset';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $errorLogsData = array();
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $resetChoice;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $licenseDataRemoved = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $cachedAssetsRemoved = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* Tools constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->wpacuFor = Misc::getVar('request', 'wpacu_for', $this->wpacuFor);
|
||||
|
||||
if ($this->wpacuFor === 'debug') {
|
||||
$isLogPHPErrors = @ini_get( 'log_errors' );
|
||||
$logPHPErrorsLocation = @ini_get( 'error_log' ) ?: 'none set';
|
||||
|
||||
$this->errorLogsData['log_status'] = $isLogPHPErrors;
|
||||
$this->errorLogsData['log_file'] = $logPHPErrorsLocation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
add_action('admin_init', array($this, 'onAdminInit'), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function onAdminInit()
|
||||
{
|
||||
if (Misc::getVar('post', 'wpacu-tools-reset')) {
|
||||
$this->doReset();
|
||||
}
|
||||
|
||||
if (Misc::getVar('post', 'wpacu-get-system-info')) {
|
||||
$this->downloadSystemInfo();
|
||||
}
|
||||
|
||||
if (Misc::getVar('post', 'wpacu-get-error-log') && is_file($this->errorLogsData['log_file'])) {
|
||||
self::downloadFile($this->errorLogsData['log_file']);
|
||||
}
|
||||
|
||||
if (! empty($_POST) && $this->wpacuFor === 'import_export') {
|
||||
$wpacuImportExport = new ImportExport();
|
||||
|
||||
// Any import/export action taken? It will reload the page if action is successful
|
||||
$wpacuImportExport->doImport();
|
||||
|
||||
// This will download the JSON through the right headers (the user will stay on the same page)
|
||||
$wpacuImportExport->doExport();
|
||||
}
|
||||
|
||||
if (isset($_GET['page']) && $_GET['page'] === WPACU_PLUGIN_ID. '_tools') {
|
||||
// "Import" Completed
|
||||
if (Misc::getVar('get', 'wpacu_import_done') && $resetDoneListArray = get_transient('wpacu_import_done')) {
|
||||
if (! is_array($resetDoneListArray)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->data['import_done_list'] = $resetDoneListArray;
|
||||
|
||||
delete_transient('wpacu_import_done');
|
||||
|
||||
// Show the confirmation that the import was completed
|
||||
add_action('wpacu_admin_notices', array($this, 'importDone'));
|
||||
}
|
||||
|
||||
// "Reset" Completed
|
||||
if (Misc::getVar('get', 'wpacu_reset_done') && $resetDoneInfo = get_transient('wpacu_reset_done')) {
|
||||
$resetDoneInfoArray = @json_decode($resetDoneInfo, ARRAY_A);
|
||||
|
||||
if (! is_array($resetDoneInfoArray)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->resetChoice = isset($resetDoneInfoArray['reset_choice']) ? $resetDoneInfoArray['reset_choice'] : '';
|
||||
$this->licenseDataRemoved = isset($resetDoneInfoArray['license_data_removed']) ? $resetDoneInfoArray['license_data_removed'] : '';
|
||||
$this->cachedAssetsRemoved = isset($resetDoneInfoArray['cached_assets_removed']) ? $resetDoneInfoArray['cached_assets_removed'] : '';
|
||||
|
||||
delete_transient('wpacu_reset_done');
|
||||
|
||||
// Show the confirmation that the reset was completed
|
||||
add_action('wpacu_admin_notices', array($this, 'resetDone'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function toolsPage()
|
||||
{
|
||||
$this->data['for'] = $this->wpacuFor;
|
||||
|
||||
if ($this->data['for'] === 'system_info') {
|
||||
$this->data['system_info'] = $this->getSystemInfo();
|
||||
}
|
||||
|
||||
if ($this->data['for'] === 'debug') {
|
||||
$this->data['error_log'] = $this->errorLogsData;
|
||||
}
|
||||
|
||||
Main::instance()->parseTemplate('admin-page-tools', $this->data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function maybeGetHost()
|
||||
{
|
||||
if ( defined( 'WPE_APIKEY' ) ) {
|
||||
$host = 'WP Engine';
|
||||
} elseif( defined( 'PAGELYBIN' ) ) {
|
||||
$host = 'Pagely';
|
||||
} elseif( DB_HOST === 'localhost:/tmp/mysql5.sock' ) {
|
||||
$host = 'ICDSoft';
|
||||
} elseif( DB_HOST === 'mysqlv5' ) {
|
||||
$host = 'NetworkSolutions';
|
||||
} elseif( strpos( DB_HOST, 'ipagemysql.com' ) !== false ) {
|
||||
$host = 'iPage';
|
||||
} elseif( strpos( DB_HOST, 'ipowermysql.com' ) !== false ) {
|
||||
$host = 'IPower';
|
||||
} elseif( strpos( DB_HOST, '.gridserver.com' ) !== false ) {
|
||||
$host = 'MediaTemple Grid';
|
||||
} elseif( strpos( DB_HOST, '.pair.com' ) !== false ) {
|
||||
$host = 'pair Networks';
|
||||
} elseif( strpos( DB_HOST, '.stabletransit.com' ) !== false ) {
|
||||
$host = 'Rackspace Cloud';
|
||||
} elseif( strpos( DB_HOST, '.sysfix.eu' ) !== false ) {
|
||||
$host = 'SysFix.eu Power Hosting';
|
||||
} elseif( strpos( $_SERVER['SERVER_NAME'], 'Flywheel' ) !== false ) {
|
||||
$host = 'Flywheel';
|
||||
} else {
|
||||
// Fallback
|
||||
$host = 'DBH: ' . DB_HOST . ', SRV: ' . $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSystemInfo()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$return = '### Begin System Info ###' . "\n";
|
||||
|
||||
$return .= "\n" . '# Site Info' . "\n";
|
||||
$return .= 'Site URL: ' . site_url() . "\n";
|
||||
$return .= 'Home URL: ' . home_url() . "\n";
|
||||
$return .= 'Multisite: ' . ( is_multisite() ? 'Yes' : 'No' ) . "\n";
|
||||
|
||||
$host = $this->maybeGetHost();
|
||||
$browser = new Browser();
|
||||
|
||||
if ($host) {
|
||||
$return .= "\n" . '# Hosting Provider' . "\n";
|
||||
$return .= 'Host: ' . $host . "\n";
|
||||
}
|
||||
|
||||
if ($browser) {
|
||||
$return .= "\n" . '# User Browser' . "\n";
|
||||
$return .= strip_tags($browser)."\n";
|
||||
}
|
||||
|
||||
// WordPress' configuration.
|
||||
// Get theme info.
|
||||
$theme_data = wp_get_theme();
|
||||
$theme = $theme_data->Name . ' ' . $theme_data->Version;
|
||||
|
||||
$return .= "\n" . '# WordPress Configuration' . "\n";
|
||||
$return .= 'Version: ' . get_bloginfo( 'version' ) . "\n";
|
||||
$return .= 'Language: ' . ( defined( 'WPLANG' ) && WPLANG ? WPLANG : 'en_US' ) . "\n";
|
||||
$return .= 'Permalink Structure: ' . ( get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default' ) . "\n";
|
||||
$return .= 'Active Theme: ' . $theme . "\n";
|
||||
$return .= 'Show On Front: ' . get_option( 'show_on_front' ) . "\n";
|
||||
|
||||
// Only show page specs if front page is set to 'page'.
|
||||
if ( get_option( 'show_on_front' ) === 'page' ) {
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
$blog_page_id = get_option( 'page_for_posts' );
|
||||
|
||||
$return .= 'Page On Front: ' . ( 0 != $front_page_id ? get_the_title( $front_page_id ) . ' (ID: ' . $front_page_id . ')' : 'Unset' ) . "\n";
|
||||
$return .= 'Page For Posts: ' . ( 0 != $blog_page_id ? get_the_title( $blog_page_id ) . ' (ID: ' . $blog_page_id . ')' : 'Unset' ) . "\n";
|
||||
}
|
||||
|
||||
$return .= 'ABSPATH: ' . ABSPATH . "\n";
|
||||
$return .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? (WP_DEBUG ? 'Enabled' : 'Disabled') : 'Not set' ) . "\n";
|
||||
$return .= 'Memory Limit: ' . WP_MEMORY_LIMIT . "\n";
|
||||
|
||||
$return .= "\n" . '# WordPress Uploads/Constants' . "\n";
|
||||
$return .= 'WP_CONTENT_DIR: ' . ( defined( 'WP_CONTENT_DIR' ) ? (WP_CONTENT_DIR ? WP_CONTENT_DIR : 'Disabled') : 'Not set' ) . "\n";
|
||||
$return .= 'WP_CONTENT_URL: ' . ( defined( 'WP_CONTENT_URL' ) ? (WP_CONTENT_URL ? WP_CONTENT_URL : 'Disabled') : 'Not set' ) . "\n";
|
||||
$return .= 'UPLOADS: ' . ( defined( 'UPLOADS' ) ? (UPLOADS ? UPLOADS : 'Disabled') : 'Not set' ) . "\n";
|
||||
|
||||
$return .= 'FS_CHMOD_DIR: ' . FS_CHMOD_DIR . "\n";
|
||||
$return .= 'FS_CHMOD_FILE: ' . FS_CHMOD_FILE . "\n";
|
||||
|
||||
$uploads_dir = wp_upload_dir();
|
||||
|
||||
$return .= 'wp_uploads_dir() path: ' . $uploads_dir['path'] . "\n";
|
||||
$return .= 'wp_uploads_dir() url: ' . $uploads_dir['url'] . "\n";
|
||||
$return .= 'wp_uploads_dir() basedir: ' . $uploads_dir['basedir'] . "\n";
|
||||
$return .= 'wp_uploads_dir() baseurl: ' . $uploads_dir['baseurl'] . "\n";
|
||||
|
||||
// Get plugins that have an update.
|
||||
$updates = get_plugin_updates();
|
||||
|
||||
// Must-use plugins.
|
||||
// NOTE: MU plugins can't show updates!
|
||||
$muplugins = get_mu_plugins();
|
||||
if ( ! empty( $muplugins ) && count( $muplugins ) > 0 ) {
|
||||
$return .= "\n" . '# Must-Use Plugins ("mu-plugins" directory)' . "\n";
|
||||
|
||||
foreach ( $muplugins as $plugin => $plugin_data ) {
|
||||
$return .= $plugin_data['Name'] . ': ' . $plugin_data['Version'] . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// WordPress active plugins.
|
||||
$return .= "\n" . '# Active Plugins ("plugins" directory)' . "\n";
|
||||
|
||||
$plugins = get_plugins();
|
||||
$active_plugins = get_option( 'active_plugins', array() );
|
||||
|
||||
foreach ( $plugins as $plugin_path => $plugin ) {
|
||||
if ( ! in_array( $plugin_path, $active_plugins, true ) ) {
|
||||
continue;
|
||||
}
|
||||
$update = array_key_exists($plugin_path, $updates) ? ' (new version available - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
||||
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
||||
}
|
||||
|
||||
// WordPress inactive plugins.
|
||||
$return .= "\n" . '# Inactive Plugins ("plugins" directory)' . "\n";
|
||||
|
||||
foreach ( $plugins as $plugin_path => $plugin ) {
|
||||
if ( in_array( $plugin_path, $active_plugins, true ) ) {
|
||||
continue;
|
||||
}
|
||||
$update = array_key_exists($plugin_path, $updates) ? ' (new version available - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
||||
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
||||
}
|
||||
|
||||
if ( is_multisite() ) {
|
||||
// WordPress Multisite active plugins.
|
||||
$return .= "\n" . '# Network Active Plugins' . "\n";
|
||||
|
||||
$plugins = wp_get_active_network_plugins();
|
||||
$active_plugins = get_site_option( 'active_sitewide_plugins', array() );
|
||||
|
||||
foreach ( $plugins as $plugin_path ) {
|
||||
$plugin_base = plugin_basename( $plugin_path );
|
||||
if ( ! array_key_exists( $plugin_base, $active_plugins ) ) {
|
||||
continue;
|
||||
}
|
||||
$update = array_key_exists($plugin_path, $updates) ? ' (new version available - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
||||
$plugin = get_plugin_data( $plugin_path );
|
||||
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Server configuration (really just versions).
|
||||
$return .= "\n" . '# Webserver Configuration' . "\n";
|
||||
$return .= 'PHP Version: ' . PHP_VERSION . "\n";
|
||||
$return .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
|
||||
$return .= 'Webserver Info: ' . $_SERVER['SERVER_SOFTWARE'] . "\n";
|
||||
|
||||
// PHP important configuration taken from php.ini
|
||||
$return .= "\n" . '# PHP Configuration' . "\n";
|
||||
$return .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
|
||||
$return .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n";
|
||||
$return .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
|
||||
$return .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
|
||||
$return .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
|
||||
$return .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
|
||||
$return .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (php.ini value: ' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
|
||||
|
||||
// PHP extensions and such.
|
||||
$return .= "\n" . '# PHP Extensions' . "\n";
|
||||
$return .= 'cURL: ' . ( function_exists( 'curl_init' ) ? 'Supported' : 'Not Supported' ) . "\n";
|
||||
$return .= 'fsockopen: ' . ( function_exists( 'fsockopen' ) ? 'Supported' : 'Not Supported' ) . "\n";
|
||||
$return .= 'SOAP Client: ' . ( class_exists( 'SoapClient' ) ? 'Installed' : 'Not Installed' ) . "\n";
|
||||
$return .= 'Suhosin: ' . ( extension_loaded( 'suhosin' ) ? 'Installed' : 'Not Installed' ) . "\n";
|
||||
|
||||
// Session stuff.
|
||||
$return .= "\n" . '# Session Configuration' . "\n";
|
||||
$return .= 'Session: ' . ( isset( $_SESSION ) ? 'Enabled' : 'Disabled' ) . "\n";
|
||||
|
||||
// The rest of this is only relevant if session is enabled.
|
||||
if ( isset( $_SESSION ) ) {
|
||||
$return .= 'Session Name: ' . esc_html( ini_get( 'session.name' ) ) . "\n";
|
||||
$return .= 'Cookie Path: ' . esc_html( ini_get( 'session.cookie_path' ) ) . "\n";
|
||||
$return .= 'Save Path: ' . esc_html( ini_get( 'session.save_path' ) ) . "\n";
|
||||
$return .= 'Use Cookies: ' . ( ini_get( 'session.use_cookies' ) ? 'On' : 'Off' ) . "\n";
|
||||
$return .= 'Use Only Cookies: ' . ( ini_get( 'session.use_only_cookies' ) ? 'On' : 'Off' ) . "\n";
|
||||
}
|
||||
|
||||
$return .= "\n" . '# '.WPACU_PLUGIN_TITLE.' Configuration '. "\n";
|
||||
|
||||
$settingsClass = new Settings();
|
||||
$settings = $settingsClass->getAll();
|
||||
|
||||
$globalUnloadList = Main::instance()->getGlobalUnload();
|
||||
|
||||
if (in_array('wp-block-library', $globalUnloadList['styles'])) {
|
||||
$settings['disable_wp_block_library'] = 1;
|
||||
}
|
||||
|
||||
if (in_array('jquery-migrate', $globalUnloadList['scripts'])) {
|
||||
$settings['disable_jquery_migrate'] = 1;
|
||||
}
|
||||
|
||||
if (in_array('comment-reply', $globalUnloadList['scripts'])) {
|
||||
$settings['disable_comment_reply'] = 1;
|
||||
}
|
||||
|
||||
$return .= 'Has read "Stripping the fat" text: '. (($settings['wiki_read'] == 1) ? 'Yes' : 'No') . "\n\n";
|
||||
|
||||
$return .= 'Manage in the Dashboard: '. (($settings['dashboard_show'] == 1) ? 'Yes ('.$settings['dom_get_type'].')' : 'No');
|
||||
|
||||
if ( ! (isset($settings['show_assets_meta_box']) && $settings['show_assets_meta_box']) ) {
|
||||
$return .= ' - Assets Meta Box is Hidden';
|
||||
}
|
||||
|
||||
if ( isset($settings['hide_options_meta_box']) && $settings['hide_options_meta_box'] ) {
|
||||
$return .= ' - Side Options Meta Box is Hidden';
|
||||
}
|
||||
|
||||
$return .= "\n";
|
||||
|
||||
$return .= 'Manage in the Front-end: '. (($settings['frontend_show'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
|
||||
if ($settings['frontend_show'] == 1 && $settings['frontend_show_exceptions']) {
|
||||
$return .= 'Do not show front-end assets when the URI contains (textarea value):' . "\n" . $settings['frontend_show_exceptions'] . "\n\n";
|
||||
}
|
||||
|
||||
$return .= 'Input Fields Style: '. ucfirst($settings['input_style'])."\n";
|
||||
$return .= 'Hide WP Files (from managing): '. (($settings['hide_core_files'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Enable "Test Mode"? '. (($settings['test_mode'] == 1) ? 'Yes' : 'No') . "\n\n";
|
||||
|
||||
$return .= 'Minify loaded CSS? '. (($settings['minify_loaded_css'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Minify loaded JS? '. (($settings['minify_loaded_js'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
|
||||
$return .= 'Combine loaded CSS? '. (($settings['combine_loaded_css'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Combine loaded JS? '. (($settings['combine_loaded_js'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
|
||||
$storageCssJsDir = WP_CONTENT_DIR . OptimizeCommon::getRelPathPluginCacheDir();
|
||||
$return .= 'CSS/JS Storage Directory: '. $storageCssJsDir . ' ('.(is_writable($storageCssJsDir) ? 'writable' : 'NON WRITABLE').')' ."\n\n";
|
||||
|
||||
$return .= 'Disable Emojis (site-wide)? '. (($settings['disable_emojis'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Disable oEmbed (Embeds) (site-wide)? '. (($settings['disable_oembed'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Disable Dashicons if Toolbar (top admin bar) is not showing (site-wide)? '. (($settings['disable_dashicons_for_guests'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Disable Gutenberg CSS Block Editor (site-wide)? '. (($settings['disable_wp_block_library'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Disable jQuery Migrate (site-wide)? '. (($settings['disable_jquery_migrate'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Disable Comment Reply (site-wide)? '. (($settings['disable_comment_reply'] == 1) ? 'Yes' : 'No') . "\n\n";
|
||||
|
||||
$return .= 'Remove "Really Simple Discovery (RSD)" link tag? '. (($settings['remove_rsd_link'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove "Windows Live Writer" link tag? '. (($settings['remove_wlw_link'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove "REST API" link tag? '. (($settings['remove_rest_api_link'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove Pages/Posts "Shortlink" tag? '. (($settings['remove_shortlink'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove "Post\'s Relational Links" tag? '. (($settings['remove_posts_rel_links'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove "WordPress version" meta tag? '. (($settings['remove_wp_version'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove All "generator" meta tags? '. (($settings['remove_generator_tag'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove Main RSS Feed Link? '. (($settings['remove_main_feed_link'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
$return .= 'Remove Comment RSS Feed Link? '. (($settings['remove_comment_feed_link'] == 1) ? 'Yes' : 'No') . "\n";
|
||||
|
||||
$xmlProtocolStatus = 'Enabled (default)';
|
||||
|
||||
if ($settings['disable_xmlrpc'] === 'disable_pingback') {
|
||||
$xmlProtocolStatus = 'Disable XML-RPC Pingback Only';
|
||||
} elseif ($settings['disable_xmlrpc'] === 'disable_all') {
|
||||
$xmlProtocolStatus = 'Disable XML-RPC Completely';
|
||||
}
|
||||
|
||||
$return .= "\n" . 'XML-RPC protocol: '. $xmlProtocolStatus . "\n";
|
||||
|
||||
$return .= "\n" . '# '.WPACU_PLUGIN_TITLE.': CSS/JS Caching Storage'. "\n";
|
||||
|
||||
$storageStats = OptimizeCommon::getStorageStats(false);
|
||||
|
||||
if (isset($storageStats['total_size'], $storageStats['total_files'])) {
|
||||
$return .= 'Total cached files: '.$storageStats['total_files'].' ('.$storageStats['total_size'].') of which '.$storageStats['total_files_assets'].' are CSS/JS assets ('.$storageStats['total_size_assets'].')';
|
||||
} else {
|
||||
$return .= 'Not used';
|
||||
}
|
||||
|
||||
$return .= "\n\n" . '# '.WPACU_PLUGIN_TITLE.': Database Storage';
|
||||
|
||||
$wpacuPluginId = WPACU_PLUGIN_ID;
|
||||
|
||||
$wpacuOptionNamesExceptions = array(
|
||||
"'".$wpacuPluginId.'_pro_license_key'."'",
|
||||
);
|
||||
|
||||
$wpacuSqlPartOptionExceptions = implode(',', $wpacuOptionNamesExceptions);
|
||||
|
||||
$sqlQueryGetOptions = <<<SQL
|
||||
SELECT option_name, option_value FROM `{$wpdb->prefix}options`
|
||||
WHERE option_name LIKE '{$wpacuPluginId}_%' AND option_name NOT IN ({$wpacuSqlPartOptionExceptions})
|
||||
SQL;
|
||||
$wpacuOptions = $wpdb->get_results($sqlQueryGetOptions, ARRAY_A);
|
||||
|
||||
$return .= "\n" . 'Table: options'."\n";
|
||||
|
||||
if (! empty($wpacuOptions)) {
|
||||
foreach ($wpacuOptions as $wpacuOption) {
|
||||
$return .= '-- Option Name: ' . $wpacuOption['option_name'] . ' / Option Value: ' . self::stripKeysWithNoValues($wpacuOption['option_value']) . "\n";
|
||||
}
|
||||
} else {
|
||||
$return .= 'No records'."\n";
|
||||
}
|
||||
|
||||
// `usermeta` and `termmeta` might have traces from the Pro version (if ever used)
|
||||
foreach (array('postmeta', 'usermeta', 'termmeta') as $tableBaseName) {
|
||||
// Get all Asset CleanUp (Pro) meta keys from all WordPress meta tables where it can be possibly used
|
||||
$wpacuGetMetaKeysQuery = <<<SQL
|
||||
SELECT * FROM `{$wpdb->prefix}{$tableBaseName}` WHERE meta_key LIKE '_{$wpacuPluginId}_%'
|
||||
SQL;
|
||||
$wpacuMetaResults = $wpdb->get_results($wpacuGetMetaKeysQuery, ARRAY_A);
|
||||
|
||||
$return .= "\n" . 'Table: '.$tableBaseName."\n";
|
||||
|
||||
if (! empty($wpacuMetaResults)) {
|
||||
foreach ($wpacuMetaResults as $metaResult) {
|
||||
$rowIdVal = '';
|
||||
|
||||
if (isset($metaResult['post_id'])) {
|
||||
$rowIdVal = 'Post ID: '.$metaResult['post_id'];
|
||||
} elseif (isset($metaResult['user_id'])) {
|
||||
$rowIdVal = 'User ID: '.$metaResult['user_id'];
|
||||
} elseif (isset($metaResult['term_id']) && term_exists((int)$metaResult['term_id'])) {
|
||||
$term = get_term($metaResult['term_id']);
|
||||
$rowIdVal = 'Taxonomy Name: '.$term->taxonomy.'; Taxonomy ID: '.$metaResult['term_id'];
|
||||
}
|
||||
|
||||
$metaValue = $metaResult['meta_value'];
|
||||
|
||||
if (trim($metaValue) === '[]') { // empty, not relevant
|
||||
continue;
|
||||
}
|
||||
|
||||
$return .= '-- ' . $rowIdVal . ' / Meta Key: ' . $metaResult['meta_key'] . ' / Meta Value: ' . $metaValue . "\n";
|
||||
}
|
||||
} else {
|
||||
$return .= 'No records'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$return .= "\n" . '### End System Info ###';
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $maybeJsonValue
|
||||
*
|
||||
* @return false|mixed|string|void
|
||||
*/
|
||||
public static function stripKeysWithNoValues($maybeJsonValue)
|
||||
{
|
||||
$arrayFromJson = @json_decode($maybeJsonValue, true);
|
||||
|
||||
if (Misc::jsonLastError() !== JSON_ERROR_NONE) {
|
||||
return $maybeJsonValue;
|
||||
}
|
||||
|
||||
if (is_array($arrayFromJson) && ! empty($arrayFromJson)) {
|
||||
foreach ($arrayFromJson as $key => $value) {
|
||||
if (! $value && empty($value)) {
|
||||
unset($arrayFromJson[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wp_json_encode($arrayFromJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. error_log file for debugging purposes
|
||||
*
|
||||
* @param $localPathToFile
|
||||
*/
|
||||
public static function downloadFile($localPathToFile)
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$date = date('j-M-Y');
|
||||
$host = parse_url(site_url(), PHP_URL_HOST);
|
||||
|
||||
header('Content-type: text/plain');
|
||||
header('Content-Disposition: attachment; filename="'.$host.'-website-errors-'.$date.'.log"');
|
||||
|
||||
echo file_get_contents($localPathToFile);
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function downloadSystemInfo()
|
||||
{
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
exit();
|
||||
}
|
||||
|
||||
if (! Misc::getVar('post', 'wpacu_get_system_info_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
\check_admin_referer('wpacu_get_system_info', 'wpacu_get_system_info_nonce');
|
||||
|
||||
$date = date('j-M-Y');
|
||||
$host = parse_url(site_url(), PHP_URL_HOST);
|
||||
|
||||
header('Content-type: text/plain');
|
||||
header('Content-Disposition: attachment; filename="'.str_replace(' ', '-', strtolower(WPACU_PLUGIN_TITLE)).'-system-info-'.$host.'-'.$date.'.txt"');
|
||||
|
||||
echo $this->getSystemInfo();
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function doReset()
|
||||
{
|
||||
// Several security checks before proceeding with the chosen action
|
||||
if (! Misc::getVar('post', 'wpacu_tools_reset_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
\check_admin_referer('wpacu_tools_reset', 'wpacu_tools_reset_nonce');
|
||||
|
||||
$wpacuResetValue = Misc::getVar('post', 'wpacu-reset', false);
|
||||
|
||||
if (! $wpacuResetValue) {
|
||||
exit('Error: Field not found, the action is not valid!');
|
||||
}
|
||||
|
||||
// Has to be confirmed
|
||||
$wpacuConfirmedValue = Misc::getVar('post', 'wpacu-action-confirmed', false);
|
||||
|
||||
if ($wpacuConfirmedValue !== 'yes') {
|
||||
exit('Error: Action needs to be confirmed.');
|
||||
}
|
||||
|
||||
if (! Menu::userCanManageAssets()) {
|
||||
exit();
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$this->resetChoice = $wpacuResetValue;
|
||||
|
||||
$wpacuPluginId = WPACU_PLUGIN_ID;
|
||||
|
||||
if ($wpacuResetValue === 'reset_settings') {
|
||||
delete_option($wpacuPluginId.'_settings');
|
||||
}
|
||||
|
||||
if (in_array($wpacuResetValue, array('reset_everything', 'reset_everything_except_settings'))) {
|
||||
// `usermeta` and `termmeta` might have traces from the Pro version (if ever used)
|
||||
foreach (array('postmeta', 'usermeta', 'termmeta') as $tableBaseName) {
|
||||
// Get all Asset CleanUp (Pro) meta keys from all WordPress meta tables where it can be possibly used
|
||||
$wpacuGetMetaKeysQuery = <<<SQL
|
||||
SELECT meta_key FROM `{$wpdb->prefix}{$tableBaseName}` WHERE meta_key LIKE '_{$wpacuPluginId}_%'
|
||||
SQL;
|
||||
$wpacuMetaKeys = $wpdb->get_col($wpacuGetMetaKeysQuery);
|
||||
|
||||
if ($tableBaseName === 'postmeta') { // e.g. Posts, Pages, Custom Post Types)
|
||||
foreach ($wpacuMetaKeys as $postMetaKey) {
|
||||
delete_post_meta_by_key($postMetaKey);
|
||||
}
|
||||
}
|
||||
|
||||
if ($tableBaseName === 'usermeta') { // User Meta: Pro version (if used)
|
||||
foreach ($wpacuMetaKeys as $userMetaKey) {
|
||||
delete_metadata('user', 0, $userMetaKey, '', true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($tableBaseName === 'termmeta') { // e.g. Taxonomy: Pro version (if used)
|
||||
foreach ($wpacuMetaKeys as $termMetaKey) {
|
||||
delete_metadata('term', 0, $termMetaKey, '', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$wpacuOptionNamesExceptions = array(
|
||||
"'".$wpacuPluginId.'_pro_license_key'."'",
|
||||
"'".$wpacuPluginId.'_pro_license_status'."'"
|
||||
);
|
||||
|
||||
// Add "Settings" to the NOT IN list to avoid clearing it
|
||||
if ($wpacuResetValue === 'reset_everything_except_settings') {
|
||||
$wpacuOptionNamesExceptions[] = "'".$wpacuPluginId.'_settings'."'";
|
||||
}
|
||||
|
||||
$wpacuSqlPartOptionExceptions = implode(',', $wpacuOptionNamesExceptions);
|
||||
|
||||
// Fetch all Asset CleanUp (Pro) options except the license key related ones
|
||||
$sqlQueryGetOptions = <<<SQL
|
||||
SELECT option_name FROM `{$wpdb->prefix}options`
|
||||
WHERE option_name LIKE '{$wpacuPluginId}_%' AND option_name NOT IN ({$wpacuSqlPartOptionExceptions})
|
||||
SQL;
|
||||
$wpacuOptionNames = $wpdb->get_col($sqlQueryGetOptions);
|
||||
|
||||
foreach ($wpacuOptionNames as $wpacuOptionName) {
|
||||
delete_option($wpacuOptionName);
|
||||
}
|
||||
|
||||
// Remove transients
|
||||
$sqlQueryGetTransients = <<<SQL
|
||||
SELECT option_name FROM `{$wpdb->prefix}options`
|
||||
WHERE option_name LIKE '_transient_{$wpacuPluginId}_%' OR option_name LIKE '_transient_timeout_{$wpacuPluginId}_%'
|
||||
OR option_name LIKE '_transient_wpacu_%' OR option_name LIKE '_transient_timeout_wpacu_%'
|
||||
SQL;
|
||||
$wpacuTransientNames = $wpdb->get_col($sqlQueryGetTransients);
|
||||
|
||||
foreach ($wpacuTransientNames as $wpacuTransientName) {
|
||||
$wpacuTransientName = str_replace(array('_transient_timeout_', '_transient_'), '', $wpacuTransientName);
|
||||
delete_transient($wpacuTransientName);
|
||||
}
|
||||
|
||||
// Remove the license data?
|
||||
if (Misc::getVar('post', 'wpacu-remove-license-data') !== '') {
|
||||
delete_option($wpacuPluginId . '_pro_license_key');
|
||||
delete_option($wpacuPluginId . '_pro_license_status');
|
||||
$this->licenseDataRemoved = true;
|
||||
}
|
||||
|
||||
// Remove all cached CSS/JS files?
|
||||
if (Misc::getVar('post', 'wpacu-remove-cache-assets') !== '') {
|
||||
$pathToCacheDirCss = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir();
|
||||
$pathToCacheDirJs = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir();
|
||||
|
||||
$allCssFiles = glob( $pathToCacheDirCss . '**/*.css' );
|
||||
$allJsFiles = glob( $pathToCacheDirJs . '**/*.js' );
|
||||
$allCachedAssets = array_merge($allCssFiles, $allJsFiles);
|
||||
|
||||
if (! empty($allCachedAssets)) {
|
||||
foreach ($allCachedAssets as $cachedAssetFile) {
|
||||
@unlink($cachedAssetFile);
|
||||
}
|
||||
}
|
||||
|
||||
$this->cachedAssetsRemoved = true;
|
||||
}
|
||||
|
||||
// Remove Asset CleanUp (Pro)'s cache transients
|
||||
$this->clearAllCacheTransients();
|
||||
}
|
||||
|
||||
// Also make 'jQuery Migrate' and 'Comment Reply' core files to load again
|
||||
// As they were enabled (not unloaded) in the default settings
|
||||
$wpacuUpdate = new Update();
|
||||
$wpacuUpdate->removeEverywhereUnloads(
|
||||
array(),
|
||||
array('jquery-migrate' => 'remove', 'comment-reply' => 'remove')
|
||||
);
|
||||
|
||||
set_transient('wpacu_reset_done',
|
||||
wp_json_encode(array(
|
||||
'reset_choice' => $this->resetChoice,
|
||||
'license_data_removed' => $this->licenseDataRemoved,
|
||||
'cached_assets_removed' => $this->cachedAssetsRemoved
|
||||
)
|
||||
),
|
||||
30
|
||||
);
|
||||
|
||||
wp_redirect(admin_url('admin.php?page=wpassetcleanup_tools&wpacu_reset_done=1&wpacu_time='.time()));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Asset CleanUp (Pro)'s Cache Transients
|
||||
*/
|
||||
public function clearAllCacheTransients()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
// Remove Asset CleanUp (Pro)'s cache transients
|
||||
$transientLikes = array(
|
||||
'_transient_wpacu_css_',
|
||||
'_transient_wpacu_js_'
|
||||
);
|
||||
|
||||
$transientLikesSql = '';
|
||||
|
||||
foreach ($transientLikes as $transientLike) {
|
||||
$transientLikesSql .= " option_name LIKE '".$transientLike."%' OR ";
|
||||
}
|
||||
|
||||
$transientLikesSql = rtrim($transientLikesSql, ' OR ');
|
||||
|
||||
$sqlQuery = <<<SQL
|
||||
SELECT option_name FROM `{$wpdb->prefix}options` WHERE {$transientLikesSql}
|
||||
SQL;
|
||||
$transientsToClear = $wpdb->get_col($sqlQuery);
|
||||
|
||||
foreach ($transientsToClear as $transientToClear) {
|
||||
$transientNameToClear = str_replace('_transient_', '', $transientToClear);
|
||||
delete_transient($transientNameToClear);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function resetDone()
|
||||
{
|
||||
$msg = '';
|
||||
|
||||
if ($this->resetChoice === 'reset_settings') {
|
||||
$msg = __('All the settings were reset to their default values.', 'wp-asset-clean-up');
|
||||
}
|
||||
|
||||
if ($this->resetChoice === 'reset_everything_except_settings') {
|
||||
$msg = __('Everything except the "Settings" was reset (including page & bulk unloads, load exceptions).', 'wp-asset-clean-up');
|
||||
}
|
||||
|
||||
if ($this->resetChoice === 'reset_everything') {
|
||||
$msg = __('Everything was reset (including settings, individual & bulk unloads, load exceptions) to the same point it was when you first activated the plugin.', 'wp-asset-clean-up');
|
||||
|
||||
if ($this->licenseDataRemoved) {
|
||||
$msg .= ' <span id="wpacu-license-data-removed-msg">'.__('The license information was also removed.', 'wp-asset-clean-up').'</span>';
|
||||
}
|
||||
|
||||
if ($this->cachedAssetsRemoved) {
|
||||
$msg .= ' <span id="wpacu-cached-assets-removed-msg">'.__('The cached CSS/JS files were also removed.', 'wp-asset-clean-up').'</span>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="updated notice wpacu-notice wpacu-reset-notice is-dismissible">
|
||||
<p><span class="dashicons dashicons-yes"></span> <?php echo wp_kses($msg, array('span' => array('id' => array()))); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function importDone()
|
||||
{
|
||||
if (empty($this->data['import_done_list'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$importedMessage = __('The following were imported:', 'wp-asset-clean-up');
|
||||
|
||||
$importedMessage .= '<ul style="list-style: disc; padding-left: 30px; margin-bottom: 0;">';
|
||||
|
||||
foreach ($this->data['import_done_list'] as $importedKey) {
|
||||
if ($importedKey === 'settings') {
|
||||
$importedMessage .= '<li>"'.esc_html__('Settings', 'wp-asset-clean-up').'"</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'homepage_unloads') {
|
||||
$importedMessage .= '<li>'.esc_html__('Homepage Unload Rules', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'homepage_exceptions') {
|
||||
$importedMessage .= '<li>'.esc_html__('Homepage Load Exceptions (for site-wide and bulk unloads)', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'sitewide_unloads') {
|
||||
$importedMessage .= '<li>'.esc_html__('Site-wide unloads', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'bulk_unloads') {
|
||||
$importedMessage .= '<li>'.esc_html__('Bulk Unloads (e.g. for all pages of `post` post type)', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'post_type_exceptions') {
|
||||
$importedMessage .= '<li>'.esc_html__('Load exceptions for all pages belonging to specific post types', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
|
||||
if ($importedKey === 'posts_metas') {
|
||||
$importedMessage .= '<li>'.esc_html__('Posts, Pages & Custom Post Types: Rules & Page Options (Side Meta Box)', 'wp-asset-clean-up').'</li>';
|
||||
}
|
||||
}
|
||||
|
||||
$importedMessage .= '</ul>';
|
||||
?>
|
||||
<div class="clearfix"></div>
|
||||
<div class="updated notice wpacu-notice wpacu-imported-notice is-dismissible">
|
||||
<p><span class="dashicons dashicons-yes"></span> <?php echo wp_kses($importedMessage, array('ul' => array('style' => array()), 'li' => array())); ?></p>
|
||||
<p>If you're using a caching plugin (e.g. WP Rocket, WP Fastest Cache, W3 Total Cache etc.) it's recommended to clear its cache if the website is working as you expect after this import, so the changes will take effect for every visitor.</p>
|
||||
</div>
|
||||
<?php
|
||||
$this->data['import_done_list'] = array(); // reset it to avoid showing it twice
|
||||
}
|
||||
}
|
1572
wp-content/plugins/wp-asset-clean-up/classes/Update.php
Normal file
1572
wp-content/plugins/wp-asset-clean-up/classes/Update.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user