Asset CleanUp: Page Speed Booster - Version 1.3.6.2

Version Description

  • Once a page is updated, the plugin preloads that page for both the admin and the guest visitor, making sure any new changes would take effect, saving the admin's time and making sure any first visitor coming to that page will access it faster (not having to wait for the caching to re-built)
  • If the attribute "data-wpacu-skip" is applied to any CSS/JS, then no alteration (e.g. no minify and no addition to any combine list) will be applied to that file (apart from the actual unload or attributes such as async/defer)
  • 'Remove All "generator" meta tags?' improvement: Higher accuracy in stripping META tag generators if the option is enabled in case some of their attributes have no quotes around them (rare cases)
  • If 'Remove "REST API" link tag?' is enabled, the /wp-json/ reference is also removed from the "Response headers" when accessing the page via remove_action()
  • Compatibility with extra page builders: "X" & "PRO" themes (Theme.co), "WP Page Builder" & "Page Builder: Live Composer" plugins: whenever their editor is ON, no unloads or any other changes to the HTML source (including minification) are performed to make sure the editor is loading its files and works smoothly
  • Compatibility with "Redis Object Cache" plugin: The global variable $wp_object_cache from the WordPress core is no longer used and it's replaced with a custom solution
  • Compatibility with "404page your smart custom 404 error page" plugin and similar plugins that are making pages as 404 customizable ones
  • For debugging purposes, the admin can use /?wpacu_no_cache to view how the website would load without the CSS/JS cache applied (the files will still be referenced from the caching directory but they will be dynamically generated instead)
  • Sometimes, large inline STYLE/SCRIPT tags' content has to be minified; if it's between 40KB and 500 KB it will be cached; any tags' content over 500KB will not be minified as it would use too many resources; it's advisable to put very large tag content into a .js external file as it would affect the TTFB (time to the first byte) when the page is loaded
  • Any inline CSS/JS associated with a handle (generated via wp_add_inline_style() and wp_add_inline_script() respectively) are automatically added to the combined file
  • Combined CSS/JS files are all stored in /wp-content/cache/asset-cleanup/("css" or "js")/ to avoid duplicated files that used to be stored in "logged-in" directory which is no longer created; This reduces the total disk space especially when the same CSS/JS is created (sometimes these files are quite large) for both guests & logged-in users
  • If "Combine loaded CSS (Stylesheets) into fewer files" is enabled, the LINK tags that are preloaded (at least two of them) will also be combined, thus reducing the number of HTTP requests
  • The method loadHTML() from DOMDocument is processing tags faster as the initial HTML source passed to it as a parameter goes through several filters, making it much smaller which makes a different in page speed when it comes to large HTML sources
  • Prevent certain DOMDocument calls (which can be slow on large HTML documents) when they are not necessary (e.g. when preloading CSS stylesheets and the RegEx which is faster can do the same task with the same accuracy)
  • Strip LINK tags that are pointing to empty content (including any inline code associated with the enqueued style added via wp_add_inline_style() function) if "CSS Files Minification" is enabled, making sure any empty tags are also stripped when "Inline CSS Files" is enabled, this saving HTTP requests and having less DOM elements
  • In some cases, the PHP function strtr() has proven to be faster than str_replace() to make replacements, thus it has been applied to some methods that are dealing with the alteration of the HTML source
  • Notify the admin that unloading 'jquery-migrate' won't unload it's "child" as well, 'jquery' (as it's a special case)
  • Fix: In rare cases, URLs to the assets are starting with ../ (it's not the best practice as this would only work depending on the page's URL structure); Make sure the file's size is calculated correctly and the right URL for the file is checked in the background to determine if it returns a 200 OK response or not
  • Fix: Store the assets info (which are shown only within the Dashboard for reference purposes) with the relative location (UR) to the asset, in case the data is later imported from a Staging to Live environment, it won't show any Staging URLs on the Live website on pages such as "Overview", thus avoiding any confusion the admin might have
  • Fix: Make sure the time dequeueing CSS/JS is calculated correctly
  • Fix: If "Asynchronous via Web Font Loader (webfont.js)" was chosen for "Combine Multiple Requests Into Fewer Ones", the font weights weren't added to the final generated SCRIPT tag
  • Fix: Make sure when the handle information is saved, there are no PHP notice errors if the 'src' index is missing as some handles do not have an "src"
Download this release

Release Info

Developer gabelivan
Plugin Icon 128x128 Asset CleanUp: Page Speed Booster
Version 1.3.6.2
Comparing to
See all releases

Code changes from version 1.3.6.1 to 1.3.6.2

assets/script.min.js CHANGED
@@ -1 +1 @@
1
- function wpacuTabOpenSettingsArea(a,b){a.preventDefault();var c,d,e;for(d=document.getElementsByClassName("wpacu-settings-tab-content"),c=0;c<d.length;c++)d[c].style.display="none";for(e=document.getElementsByClassName("wpacu-settings-tab-link"),c=0;c<e.length;c++)e[c].className=e[c].className.replace(" active","");document.getElementById(b).style.display="table-cell",jQuery('a[href="#'+b+'"]').addClass("active"),jQuery("#wpacu-selected-tab-area").val(b)}function wpacuBytesToSize(a){return 0===a?"N/A":(a/1024).toFixed(4)+" KB"}function wpacuAjaxClearCache(){jQuery.post(wpacu_object.ajax_url+"?wpacu_clear_cache",{action:wpacu_object.plugin_id+"_clear_cache",time_r:(new Date).getTime()},function(a){setTimeout(function(){wpacuClearAutoptimizeCache()},150)})}function wpacuClearAutoptimizeCache(){jQuery("#wp-admin-bar-autoptimize-default li").length>0&&void 0!==autoptimize_ajax_object.ajaxurl&&void 0!==autoptimize_ajax_object.nonce&&jQuery.ajax({type:"GET",url:autoptimize_ajax_object.ajaxurl,data:{action:"autoptimize_delete_cache",nonce:autoptimize_ajax_object.nonce},dataType:"json",cache:!1,timeout:9e3,success:function(a){},error:function(a,b){}})}jQuery(document).ready(function(a){function b(){if(!a("#wpacu_ajax_fetch_assets_list_dashboard_view").length)return!1;var b,c,d,f,g,h={};"direct"===wpacu_object.dom_get_type?(h[wpacu_object.plugin_name+"_load"]=1,h[wpacu_object.plugin_name+"_time_r"]=(new Date).getTime(),a.ajax({method:"GET",url:wpacu_object.page_url,data:h,cache:!1,complete:function(b,c){if("error"===b.statusText){f=b.responseText.replace(/(<([^>]+)>)/gi,"");try{f=String(f).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}catch(a){console.log(a)}g=wpacu_object.ajax_direct_fetch_error,g=g.replace(/{wpacu_output}/,f),g=g.replace(/{wpacu_status_code_error}/,b.status),a("#wpacu_meta_box_content").html(g)}}}).done(function(f){if(f.lastIndexOf(wpacu_object.start_del_e)<0||f.lastIndexOf(wpacu_object.end_del_e)<0||f.lastIndexOf(wpacu_object.start_del_h)<0||f.lastIndexOf(wpacu_object.end_del_h)<0){g=wpacu_object.ajax_direct_fetch_error_with_success_response,g=g.replace(/{wpacu_output}/,xhr.responseText.replace(/(<([^>]+)>)/gi,""));try{g=String(g).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}catch(a){console.log(a)}return void a("#wpacu_meta_box_content").html(g)}c=f.substring(f.lastIndexOf(wpacu_object.start_del_e)+wpacu_object.start_del_e.length,f.lastIndexOf(wpacu_object.end_del_e)),d=f.substring(f.lastIndexOf(wpacu_object.start_del_h)+wpacu_object.start_del_h.length,f.lastIndexOf(wpacu_object.end_del_h)),b={action:wpacu_object.plugin_name+"_get_loaded_assets",wpacu_list_e:c,wpacu_list_h:d,post_id:wpacu_object.post_id,page_url:wpacu_object.page_url,tag_id:wpacu_object.tag_id,wpacu_taxonomy:wpacu_object.wpacu_taxonomy,time_r:(new Date).getTime()},a.post(wpacu_object.ajax_url,b,function(b){b&&(a("#wpacu_meta_box_content").html(b),a("#wpacu_home_page_form").length>0&&a("#submit").show(),setTimeout(function(){e.load(),a(".wpacu_asset_row").removeClass("wpacu-loading"),a("#wpacu-assets-reloading").remove(),e.checkSourcesFor404Errors()},200))})})):"wp_remote_post"===wpacu_object.dom_get_type&&(b={action:wpacu_object.plugin_name+"_get_loaded_assets",post_id:wpacu_object.post_id,page_url:wpacu_object.page_url,tag_id:wpacu_object.tag_id,wpacu_taxonomy:wpacu_object.wpacu_taxonomy,time_r:(new Date).getTime()},a.post(wpacu_object.ajax_url,b,function(b){if(!b)return!1;a("#wpacu_meta_box_content").html(b),a("#wpacu_home_page_form").length>0&&a("#submit").show(),setTimeout(function(){e.load(),setTimeout(function(){e.checkSourcesFor404Errors()},100)},200)}))}a('input[name="wpacu_sub_tab_area"]').click(function(){a(this).prop("checked")&&a("#wpacu-selected-sub-tab-area").val(a(this).val())}),a("#wpacu_minify_css_enable, #wpacu_combine_loaded_css_enable, #wpacu_minify_js_enable, #wpacu_combine_loaded_js_enable, #wpacu_cdn_rewrite_enable, #wpacu_enable_test_mode").click(function(){a(this).prop("checked")?a('[data-linked-to="'+a(this).attr("id")+'"]').find(".wpacu-circle-status").addClass("wpacu-on").removeClass("wpacu-off"):a('[data-linked-to="'+a(this).attr("id")+'"]').find(".wpacu-circle-status").addClass("wpacu-off").removeClass("wpacu-on")}),a(document).on("click","#wpacu_inline_css_files_below_size_checkbox",function(){a(this).is(":checked")?a("#wpacu_inline_css_files_enable").prop("checked",!0).trigger("tick"):""===a("#wpacu_inline_css_files_list").val()&&a("#wpacu_inline_css_files_enable").prop("checked",!1).trigger("tick")}),a(document).on("click","#wpacu_inline_js_files_below_size_checkbox",function(){if(a(this).is(":checked")){if(!confirm(wpacu_object.inline_auto_js_files_confirm_msg))return!1;a("#wpacu_inline_js_files_enable").prop("checked",!0).trigger("tick")}else""===a("#wpacu_inline_js_files_list").val()&&a("#wpacu_inline_js_files_enable").prop("checked",!1).trigger("tick")}),a("#wpacu-mark-license-valid-button").click(function(){return confirm(wpacu_object.mark_license_valid_confirm)}),a("#wpacu-license-form").submit(function(){a("#edd_license_activate_btn").attr("disabled","disabled"),a("#edd_license_deactivate_btn").attr("disabled","disabled"),a(".wpacu-license-spinner").show()});var c,d;a("#wpacu-reset-drop-down").on("change keyup keydown mouseup mousedown click",function(){""===a(this).val()?(a("#wpacu-warning-read").removeClass("wpacu-visible"),a("#wpacu-reset-submit-btn").attr("disabled","disabled").removeClass("button-primary").addClass("button-secondary")):("reset_everything"===a(this).val()?a("#wpacu-license-data-remove-area, #wpacu-cache-assets-remove-area").addClass("wpacu-visible"):a("#wpacu-license-data-remove-area, #wpacu-cache-assets-remove-area").removeClass("wpacu-visible"),a("#wpacu-warning-read").addClass("wpacu-visible"),a("#wpacu-reset-submit-btn").removeAttr("disabled").removeClass("button-secondary").addClass("button-primary")),a(".wpacu-tools-area .wpacu-warning").hide(),c=a(this).find("option:selected"),a("#"+c.attr("data-id")).show()}),a("#wpacu-reset-submit-btn").on("click",function(){if("reset_settings"===a("#wpacu-reset-drop-down").val()?d=wpacu_object.reset_settings_confirm_msg:"reset_everything_except_settings"===a("#wpacu-reset-drop-down").val()?d=wpacu_object.reset_everything_except_settings_confirm_msg:"reset_everything"===a("#wpacu-reset-drop-down").val()&&(d=wpacu_object.reset_everything_confirm_msg),!confirm(d))return!1;a("#wpacu-action-confirmed").val("yes"),setTimeout(function(){"yes"===a("#wpacu-action-confirmed").val()&&a("#wpacu-tools-form").submit()},1e3)}),a("#wpacu-import-form").submit(function(){if(!confirm(wpacu_object.import_confirm_msg))return!1;a(this).find("button").addClass("wpacu-importing").prop("disabled",!0)});var e={load:function(){var b,c,d,f=".input-unload-on-this-page.wpacu-not-locked";a(".input-unload-on-this-page").on("click change",function(f){if(b=a(this).attr("data-handle"),c=a(this).hasClass("wpacu_unload_rule_for_style")?"style":"script",a(this).prop("checked")){if("click"===f.type&&!e.triggerAlertWhenAnyUnloadRuleIsChosen(b,c))return!1;e.uncheckAllOtherBulkUnloadRules(a(this),!1),e.showHandleLoadExceptionArea(c,b),a(this).closest("tr").addClass("wpacu_not_load")}else a(this).closest("tr").removeClass("wpacu_not_load"),d=a(this).parents(".wpacu_asset_row"),e.hideHandleLoadExceptionArea(d,b,c)}),a(".wpacu-plugin-check-all").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin");a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]').find(f).prop("checked",!0).closest("tr").addClass("wpacu_not_load")}),a(".wpacu-plugin-uncheck-all").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin");a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]').find(f).prop("checked",!1).closest("tr").removeClass("wpacu_not_load")}),a(".wpacu-plugin-check-load-all").on("click change",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin"),d=a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]');d.find(".wpacu_load_it_option_one.wpacu_load_exception").prop("checked",!0).closest("tr.wpacu_is_bulk_unloaded").removeClass("wpacu_not_load"),d.find(f).prop("checked",!1).trigger("change")}),a(".wpacu-plugin-uncheck-load-all").on("click change",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin"),d=a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]');d.find(".wpacu_load_it_option_one.wpacu_load_exception").prop("checked",!1).closest("tr.wpacu_is_bulk_unloaded").addClass("wpacu_not_load"),d.find(f).prop("checked",!1).trigger("change")}),a(".wpacu_keep_bulk_rule").click(function(){a(this).prop("checked")&&a(this).parents("li").next().removeClass("remove_rule")}),a(".wpacu_remove_bulk_rule").click(function(){a(this).prop("checked")&&a(this).parents("li").addClass("remove_rule")}),a(".wpacu_bulk_unload").on("click change",function(f){b=a(this).attr("data-handle"),c=a(this).attr("data-handle-for"),d=a("[data-"+c+'-handle-row="'+b+'"]');var g=a(this).parents("li");if(a(this).prop("checked")){if("click"===f.type&&!e.triggerAlertWhenAnyUnloadRuleIsChosen(b,c))return!1;a(this).hasClass("wpacu_unload_it_regex_checkbox")?(g.find("label").addClass("wpacu_unload_checked"),g.find("textarea").prop("disabled",!1).focus().removeClass("wpacu_disabled"),g.find(".wpacu_handle_unload_regex_input_wrap").removeClass("wpacu_hide")):(a(this).parent("label").addClass("wpacu_input_load_checked"),a(this).closest("tr").addClass("wpacu_not_load")),e.showHandleLoadExceptionArea(c,b),a(this).hasClass("wpacu_global_unload")?(e.uncheckAllOtherBulkUnloadRules(a(this),!0),a('.input-unload-on-this-page[data-handle-for="'+c+'"][data-handle="'+b+'"]').prop("checked",!1)):a(this).hasClass("wpacu_post_type_unload")&&(e.uncheckAllOtherBulkUnloadRules(a(this),!1),a('.input-unload-on-this-page[data-handle-for="'+c+'"][data-handle="'+b+'"]').prop("checked",!1))}else a(this).hasClass("wpacu_unload_it_regex_checkbox")?(g.find("label").removeClass("wpacu_unload_checked"),g.find("textarea").blur().addClass("wpacu_disabled"),""===g.find("textarea").val().trim()&&(g.find("textarea").prop("disabled",!0).val(""),g.find(".wpacu_handle_unload_regex_input_wrap").addClass("wpacu_hide"))):(a(this).parent("label").removeClass("wpacu_input_load_checked"),a(this).closest("tr").removeClass("wpacu_not_load")),e.hideHandleLoadExceptionArea(d,b,c);d.hasClass("wpacu_is_bulk_unloaded")||a(".wpacu_bulk_unload:not(.wpacu_unload_it_regex_checkbox)").is(":checked")||a(this).closest("tr").removeClass("wpacu_not_load")}),a(".wpacu_load_it_option_one.wpacu_load_exception").on("click change",function(){var b=a(this).attr("data-handle");if(a(this).prop("checked")){a(this).parent("label").addClass("wpacu_global_unload_exception");var c="";a(this).hasClass("wpacu_style")?c="style":a(this).hasClass("wpacu_script")&&(c="script"),a("#"+c+"_"+b).prop("checked",!1).trigger("change")}else a(this).parent("label").removeClass("wpacu_global_unload_exception")}),a(".wpacu_load_it_option_two").on("click change",function(){var b=a(this).parents("li");a(this).prop("checked")?(b.find("label").addClass("wpacu_bold"),b.find("textarea").prop("disabled",!1).focus().removeClass("wpacu_disabled"),b.find(".wpacu_load_regex_input_wrap").removeClass("wpacu_hide")):(b.find("label").removeClass("wpacu_bold"),b.find("textarea").blur().addClass("wpacu_disabled"),""===b.find("textarea").val().trim()&&(b.find("textarea").prop("disabled",!0).val(""),b.find(".wpacu_load_regex_input_wrap").addClass("wpacu_hide")))}),a(".wpacu_script_attr_rule_input").on("click change",function(){a(this).is(":checked")&&(a(this).parents("ul").find(".wpacu_script_attr_rule_input").not(a(this)).prop("checked",!1),a(this).hasClass("wpacu_script_attr_rule_global")&&a(this).parents("ul").find(".wpacu-script-attr-make-exception").removeClass("wpacu_hide")),a(this).parents("ul").find(".wpacu_script_attr_rule_global").is(":checked")||a(this).parents("ul").find(".wpacu-script-attr-make-exception").addClass("wpacu_hide")}),a(".wpacu-add-handle-note").on("click",function(b){b.preventDefault();var c,d,e=a(this).attr("data-handle");a(this).hasClass("wpacu-for-script")?c=a('.wpacu-handle-notes-field[data-script-handle="'+e+'"]'):a(this).hasClass("wpacu-for-style")&&(c=a('.wpacu-handle-notes-field[data-style-handle="'+e+'"]')),c.length<1||(d=c.find(":input"),c.is(":hidden")?(c.show(),d.prop("disabled",!1)):(c.hide(),""===d.val().trim()&&"true"===d.attr("data-wpacu-is-empty-on-page-load")&&d.prop("disabled",!0).val("")))}),a(".wpacu-external-file-size").on("click",function(b){b.preventDefault();var c,d=a(this),e=d.attr("data-src");d.hide(),c=d.next(),c.show(),e.includes("/?")?a.get(e,{},function(a,b,d){if("success"!==b)return"N/A";c.html(wpacuBytesToSize(a.length))}):a.post(wpacu_object.ajax_url,{action:wpacu_object.plugin_id+"_get_external_file_size",wpacu_remote_file:e},function(a){c.html(a)})}),a(".wpacu_handle_row_expand_contract").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-handle"),d=a(this).attr("data-wpacu-handle-for");a(this).find("span").hasClass("dashicons-minus")?(a(this).parents("td").attr("data-wpacu-row-status","contracted").find(".wpacu_handle_row_expanded_area").addClass("wpacu_hide"),a(this).find("span").removeClass("dashicons-minus").addClass("dashicons-plus"),a("#wpacu_"+d+"_"+c+"_row_contracted_area").val("1")):a(this).find("span").hasClass("dashicons-plus")&&(a(this).parents("td").attr("data-wpacu-row-status","expanded").find(".wpacu_handle_row_expanded_area").removeClass("wpacu_hide"),a(this).find("span").removeClass("dashicons-plus").addClass("dashicons-minus"),a("#wpacu_"+d+"_"+c+"_row_contracted_area").val(""))});a('[data-is-hardcoded-asset="true"]').length>0&&(a.each(a('[data-is-hardcoded-asset="true"]'),function(b,c){e.updateHardcodedDataHiddenFieldStatus(a(this))}),a('[data-is-hardcoded-asset="true"]').on("click",".wpacu_unload_rule_input",function(){e.updateHardcodedDataHiddenFieldStatus(a(this).parents("[data-is-hardcoded-asset]"))}))},updateHardcodedDataHiddenFieldStatus:function(b){var c=!1;b.is("[data-style-handle-row]")?c=b.attr("data-style-handle-row"):b.is("[data-script-handle-row]")&&(c=b.attr("data-script-handle-row")),c&&(b.find(".wpacu_unload_rule_input:checked").length>0||b.hasClass("wpacu_not_load")?a("#"+c+"_hardcoded_data").prop("disabled",!1):a("#"+c+"_hardcoded_data").prop("disabled",!0))},triggerAlertWhenAnyUnloadRuleIsChosen:function(b,c){if("dashicons"===b&&"style"===c&&a('input[name="wpacu_ignore_child[styles][nf-display]').length>0&&!confirm(wpacu_object.dashicons_unload_alert_ninja_forms))return!1;if("script"===c){if(("jquery"===b||"jquery-core"===b)&&a("#script_jquery_ignore_children").length>0&&!confirm(wpacu_object.jquery_unload_alert))return!1;if(("backbone"===b||"underscore"===b)&&!confirm(wpacu_object.sensitive_library_unload_alert))return!1}return!0},pluginLoadManager:function(){a(".wpacu_plugin_load_it").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")&&(e.hidePluginLoadExceptionArea(b),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),a('.wpacu_plugin_unload_site_wide[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_radio[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"))}),a(".wpacu_plugin_unload_site_wide").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?(a(this).parent("label").addClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_radio[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),e.showPluginLoadExceptionArea(b)):(a(this).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!0))}),a(".wpacu_plugin_unload_regex_radio").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?(a(this).parent("label").addClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide"),e.showPluginLoadExceptionArea(b),a('.wpacu_plugin_unload_site_wide[data-wpacu-plugin-path="'+b+'"]').prop("checked",!1).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked")):(a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),a(this).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"))}),a(".wpacu_plugin_load_exception_regex").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?a('.wpacu_load_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide"):a('.wpacu_load_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide")})},showPluginLoadExceptionArea:function(b){a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!1)},hidePluginLoadExceptionArea:function(b){a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!0)},showHandleLoadExceptionArea:function(b,c){var d=a("div.wpacu_exception_options_area_wrap[data-"+b+'-handle="'+c+'"]');d.parent("div").removeClass("wpacu_hide"),d.find('input[type="checkbox"]').prop("disabled",!1)},hideHandleLoadExceptionArea:function(b,c,d){if(!b.hasClass("wpacu_is_bulk_unloaded")&&!b.find(".wpacu_bulk_unload").is(":checked")){var e=a("div.wpacu_exception_options_area_wrap[data-"+d+'-handle="'+c+'"]');e.parent("div").addClass("wpacu_hide"),e.find('input[type="checkbox"]').prop("disabled",!0)}},uncheckAllOtherBulkUnloadRules:function(a,b){var c=".wpacu_bulk_unload";!1===b&&(c=".wpacu_bulk_unload:not(.wpacu_unload_it_regex_checkbox)"),a.closest("tr").find(c).not(a).prop("checked",!1).parent("label").removeClass("wpacu_input_load_checked").removeClass("wpacu_unload_checked")},checkSourcesFor404Errors:function(){var b=a("[data-wpacu-external-source]");if(!(b.length<1)){var c=b.length,d="";b.each(function(b){var e=a(this),f=e.attr("data-wpacu-external-source");d+=f+"-at-wpacu-at-",b===c-1&&jQuery.post(wpacu_object.ajax_url+"?wpacu_check_external_url",{action:wpacu_object.plugin_id+"_check_external_urls_for_status_code",wpacu_check_urls:d},function(b){var c=jQuery.parseJSON(b);a.each(c,function(b,c){a('[data-wpacu-external-source="'+c+'"]').css({color:"#cc0000"}).parent("div").find("[data-wpacu-external-source-status]").html('<small>* <em style="font-weight: 600;">'+wpacu_object.source_load_error_msg+"</em></small>")})})})}}};a(window).load(function(){e.checkSourcesFor404Errors()}),a("#wpacu_post_type_select").change(function(){a("#wpacu_post_type_form").submit()}),a("#wpacu_taxonomy_select").change(function(){a("#wpacu_taxonomy_form").submit()}),a("#wpacu_dashboard").click(function(){a(this).prop("checked")?a("#wpacu-settings-assets-retrieval-mode").show():a("#wpacu-settings-assets-retrieval-mode").hide()}),a(".wpacu-dom-get-type-selection").change(function(){a(this).is(":checked")&&(a(".wpacu-dom-get-type-info").hide(),a("#"+a(this).attr("data-target")).fadeIn("fast"))}),a("#wpacu_frontend").click(function(){a(this).prop("checked")?a("#wpacu-settings-frontend-exceptions").show():a("#wpacu-settings-frontend-exceptions").hide()}),a(".google_fonts_combine_type").change(function(){a(".wpacu_google_fonts_combine_type_area").hide(),"async"===a(this).val()?a("#wpacu_google_fonts_combine_type_async_info_area").fadeIn():"async_preload"===a(this).val()?a("#wpacu_google_fonts_combine_type_async_preload_info_area").fadeIn():a("#wpacu_google_fonts_combine_type_rb_info_area").fadeIn()}),a("#wpacu_assets_list_layout").on("click change",function(){"by-location"===a(this).val()?a("#wpacu-assets-list-by-location-selected").fadeIn("fast"):a("#wpacu-assets-list-by-location-selected").fadeOut("fast")}),a("#wpacu_disable_jquery_migrate").on("click",function(){return!a(this).is(":checked")||(!(!a(this).is(":checked")||!confirm(wpacu_object.jquery_migration_disable_confirm_msg))||(a(this).prop("checked",!1),!1))}),a("#wpacu_disable_comment_reply").on("click",function(){return!a(this).is(":checked")||(!(!a(this).is(":checked")||!confirm(wpacu_object.comment_reply_disable_confirm_msg))||(a(this).prop("checked",!1),!1))}),a("[data-target-opacity]").on("click change tick",function(){a(this).prop("checked")?a("#"+a(this).attr("data-target-opacity")).css({opacity:1}):a("#"+a(this).attr("data-target-opacity")).css({opacity:.4})}),a(".wpacu-combine-loaded-js-level").change(function(){a(this).is(":checked")&&(a(".wpacu_combine_loaded_js_level_area").removeClass("wpacu_active"),a("#"+a(this).attr("data-target")).addClass("wpacu_active"))});var f=a('#wpacu-update-button-area input[type="submit"]');f.parents("form").submit(function(){f.attr("disabled",!0),a("#wpacu-updating-settings").show()});var g=a("#wpacu-update-front-settings-area .wpacu_update_btn");if(g.parents("form").submit(function(){return g.attr("disabled",!0).addClass("wpacu_submitting"),a("#wpacu-updating-front-settings").show(),!0}),a("form#wpacu-settings-form, form#wpacu_home_page_form").submit(function(){return f.attr("disabled",!0),!0}),a(".wpacu_bulk_rule_checkbox, .wpacu_remove_preload").click(function(){var b=a(this).parents(".wpacu_bulk_change_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a(".wpacu_remove_regex").click(function(){var b=a(this).parents(".wpacu_regex_rule_row");a(this).prop("checked")?b.addClass("wpacu_enabled"):b.removeClass("wpacu_enabled")}),a(".wpacu_restore_position").click(function(){var b=a(this).parents(".wpacu_restore_position_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a(".wpacu_remove_global_attr").click(function(){var b=a(this).parents(".wpacu_remove_global_attr_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a("#wpacu_wrap_assets").length>0&&setTimeout(function(){e.load()},200),a("#wpacu-plugins-load-manager-wrap").length>0&&setTimeout(function(){e.pluginLoadManager()},200),"undefined"==typeof wpacu_object||a("#wpacu_meta_box_content").length<1)return!1;("default"===wpacu_object.list_show_status||""===wpacu_object.list_show_status||wpacu_object.override_assets_list_load)&&b(),"fetch_on_click"===wpacu_object.list_show_status&&a("#wpacu_ajax_fetch_on_click_btn").click(function(c){c.preventDefault(),a(this).hide(),a("#wpacu_fetching_assets_list_wrap").show(),b()}),a(document).on("click",".wp-admin.post-php .edit-post-header__settings button.is-primary",function(){var c=function(){if(0===a(".edit-post-header__settings .is-saving").length){if(a("#wpacu_unload_assets_area_loaded").length>0&&a("#wpacu_unload_assets_area_loaded").val()){a("#wpacu-assets-reloading").remove();var c='<span id="wpacu-assets-reloading" class="editor-post-saved-state is-wpacu-reloading">'+wpacu_object.reload_icon+wpacu_object.reload_msg+"</span>";a(".wp-admin.post-php .edit-post-header__settings").prepend(c)}a(".wpacu_asset_row").addClass("wpacu-loading"),b(),wpacuAjaxClearCache(),clearInterval(d)}},d=setInterval(c,900)})}),""!==wpacu_object.clear_cache_on_page_load&&wpacuAjaxClearCache(),""!==wpacu_object.clear_other_caches&&setTimeout(function(){wpacuClearAutoptimizeCache()},150),jQuery(document).ready(function(a){try{var b;a('input[type="hidden"][name="_wp_http_referer"]').length>0&&(b=a('input[type="hidden"][name="_wp_http_referer"]').val(),b.includes("term.php?taxonomy=")&&b.includes("message=")&&wpacuAjaxClearCache(),b.includes("post.php?post=")&&b.includes("message=")&&wpacuAjaxClearCache())}catch(a){console.log(a)}});
1
+ function wpacuTabOpenSettingsArea(a,b){a.preventDefault();var c,d,e;for(d=document.getElementsByClassName("wpacu-settings-tab-content"),c=0;c<d.length;c++)d[c].style.display="none";for(e=document.getElementsByClassName("wpacu-settings-tab-link"),c=0;c<e.length;c++)e[c].className=e[c].className.replace(" active","");document.getElementById(b).style.display="table-cell",jQuery('a[href="#'+b+'"]').addClass("active"),jQuery("#wpacu-selected-tab-area").val(b)}function wpacuBytesToSize(a){return 0===a?"N/A":(a/1024).toFixed(4)+" KB"}function wpacuAjaxClearCache(){jQuery.post(wpacu_object.ajax_url+"?wpacu_clear_cache",{action:wpacu_object.plugin_id+"_clear_cache",time_r:(new Date).getTime()},function(a){setTimeout(function(){wpacuClearAutoptimizeCache(),wpacu_object.is_frontend_view?jQuery.post(wpacu_object.ajax_url+"?wpacu_preload_guest",{action:wpacu_object.plugin_id+"_preload",page_url:wpacu_object.page_url,time_r:(new Date).getTime()}):jQuery.get(wpacu_object.page_url,{wpacu_preload:1,wpacu_no_frontend_show:1,time_r:(new Date).getTime()},function(){jQuery.post(wpacu_object.ajax_url+"?wpacu_preload_guest",{action:wpacu_object.plugin_id+"_preload",page_url:wpacu_object.page_url,time_r:(new Date).getTime()})})},150)})}function wpacuClearAutoptimizeCache(){jQuery("#wp-admin-bar-autoptimize-default li").length>0&&void 0!==autoptimize_ajax_object.ajaxurl&&void 0!==autoptimize_ajax_object.nonce&&jQuery.ajax({type:"GET",url:autoptimize_ajax_object.ajaxurl,data:{action:"autoptimize_delete_cache",nonce:autoptimize_ajax_object.nonce},dataType:"json",cache:!1,timeout:9e3,success:function(a){},error:function(a,b){}})}jQuery(document).ready(function(a){function b(){if(!a("#wpacu_ajax_fetch_assets_list_dashboard_view").length)return!1;var b={};if("direct"===wpacu_object.dom_get_type)b[wpacu_object.plugin_name+"_load"]=1,b[wpacu_object.plugin_name+"_time_r"]=(new Date).getTime(),a.ajax({method:"GET",url:wpacu_object.page_url,data:b,cache:!1,complete:function(b,d){if("error"===b.statusText){if(404===b.status)return void c(b.responseText,b.status);var e=b.responseText.replace(/(<([^>]+)>)/gi,"");try{e=String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}catch(a){console.log(a)}var f=wpacu_object.ajax_direct_fetch_error;f=f.replace(/{wpacu_output}/,e),f=f.replace(/{wpacu_status_code_error}/,b.status),a("#wpacu_meta_box_content").html(f)}}}).done(function(a){c(a)});else if("wp_remote_post"===wpacu_object.dom_get_type){var d={action:wpacu_object.plugin_name+"_get_loaded_assets",post_id:wpacu_object.post_id,page_url:wpacu_object.page_url,tag_id:wpacu_object.tag_id,wpacu_taxonomy:wpacu_object.wpacu_taxonomy,time_r:(new Date).getTime()};a.post(wpacu_object.ajax_url,d,function(b){if(!b)return!1;a("#wpacu_meta_box_content").html(b),a("#wpacu_home_page_form").length>0&&a("#submit").show(),setTimeout(function(){f.load(),setTimeout(function(){f.checkSourcesFor404Errors()},100)},200)})}}function c(b,c){if(b.lastIndexOf(wpacu_object.start_del_e)<0||b.lastIndexOf(wpacu_object.end_del_e)<0||b.lastIndexOf(wpacu_object.start_del_h)<0||b.lastIndexOf(wpacu_object.end_del_h)<0){var d=wpacu_object.ajax_direct_fetch_error_with_success_response;d=d.replace(/{wpacu_output}/,xhr.responseText.replace(/(<([^>]+)>)/gi,""));try{d=String(d).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}catch(a){console.log(a)}return void a("#wpacu_meta_box_content").html(d)}var e=b.substring(b.lastIndexOf(wpacu_object.start_del_e)+wpacu_object.start_del_e.length,b.lastIndexOf(wpacu_object.end_del_e)),g=b.substring(b.lastIndexOf(wpacu_object.start_del_h)+wpacu_object.start_del_h.length,b.lastIndexOf(wpacu_object.end_del_h)),h={action:wpacu_object.plugin_name+"_get_loaded_assets",wpacu_list_e:e,wpacu_list_h:g,post_id:wpacu_object.post_id,page_url:wpacu_object.page_url,tag_id:wpacu_object.tag_id,wpacu_taxonomy:wpacu_object.wpacu_taxonomy,time_r:(new Date).getTime()};a.post(wpacu_object.ajax_url,h,function(b){b&&(a("#wpacu_meta_box_content").html(b),404===c&&a("#wpacu_meta_box_content").prepend('<p><span class="dashicons dashicons-warning"></span> '+wpacu_object.server_returned_404_not_found+"</p><hr />"),a("#wpacu_home_page_form").length>0&&a("#submit").show(),setTimeout(function(){f.load(),a(".wpacu_asset_row").removeClass("wpacu-loading"),a("#wpacu-assets-reloading").remove(),f.checkSourcesFor404Errors()},200))})}a('input[name="wpacu_sub_tab_area"]').click(function(){a(this).prop("checked")&&a("#wpacu-selected-sub-tab-area").val(a(this).val())}),a("#wpacu_minify_css_enable, #wpacu_combine_loaded_css_enable, #wpacu_minify_js_enable, #wpacu_combine_loaded_js_enable, #wpacu_cdn_rewrite_enable, #wpacu_enable_test_mode").click(function(){a(this).prop("checked")?a('[data-linked-to="'+a(this).attr("id")+'"]').find(".wpacu-circle-status").addClass("wpacu-on").removeClass("wpacu-off"):a('[data-linked-to="'+a(this).attr("id")+'"]').find(".wpacu-circle-status").addClass("wpacu-off").removeClass("wpacu-on")}),a(document).on("click","#wpacu_inline_css_files_below_size_checkbox",function(){a(this).is(":checked")?a("#wpacu_inline_css_files_enable").prop("checked",!0).trigger("tick"):""===a("#wpacu_inline_css_files_list").val()&&a("#wpacu_inline_css_files_enable").prop("checked",!1).trigger("tick")}),a(document).on("click","#wpacu_inline_js_files_below_size_checkbox",function(){if(a(this).is(":checked")){if(!confirm(wpacu_object.inline_auto_js_files_confirm_msg))return!1;a("#wpacu_inline_js_files_enable").prop("checked",!0).trigger("tick")}else""===a("#wpacu_inline_js_files_list").val()&&a("#wpacu_inline_js_files_enable").prop("checked",!1).trigger("tick")}),a("#wpacu-mark-license-valid-button").click(function(){return confirm(wpacu_object.mark_license_valid_confirm)}),a("#wpacu-license-form").submit(function(){a("#edd_license_activate_btn").attr("disabled","disabled"),a("#edd_license_deactivate_btn").attr("disabled","disabled"),a(".wpacu-license-spinner").show()});var d,e;a("#wpacu-reset-drop-down").on("change keyup keydown mouseup mousedown click",function(){""===a(this).val()?(a("#wpacu-warning-read").removeClass("wpacu-visible"),a("#wpacu-reset-submit-btn").attr("disabled","disabled").removeClass("button-primary").addClass("button-secondary")):("reset_everything"===a(this).val()?a("#wpacu-license-data-remove-area, #wpacu-cache-assets-remove-area").addClass("wpacu-visible"):a("#wpacu-license-data-remove-area, #wpacu-cache-assets-remove-area").removeClass("wpacu-visible"),a("#wpacu-warning-read").addClass("wpacu-visible"),a("#wpacu-reset-submit-btn").removeAttr("disabled").removeClass("button-secondary").addClass("button-primary")),a(".wpacu-tools-area .wpacu-warning").hide(),d=a(this).find("option:selected"),a("#"+d.attr("data-id")).show()}),a("#wpacu-reset-submit-btn").on("click",function(){if("reset_settings"===a("#wpacu-reset-drop-down").val()?e=wpacu_object.reset_settings_confirm_msg:"reset_everything_except_settings"===a("#wpacu-reset-drop-down").val()?e=wpacu_object.reset_everything_except_settings_confirm_msg:"reset_everything"===a("#wpacu-reset-drop-down").val()&&(e=wpacu_object.reset_everything_confirm_msg),!confirm(e))return!1;a("#wpacu-action-confirmed").val("yes"),setTimeout(function(){"yes"===a("#wpacu-action-confirmed").val()&&a("#wpacu-tools-form").submit()},1e3)}),a("#wpacu-import-form").submit(function(){if(!confirm(wpacu_object.import_confirm_msg))return!1;a(this).find("button").addClass("wpacu-importing").prop("disabled",!0)});var f={load:function(){var b,c,d,e=".input-unload-on-this-page.wpacu-not-locked";a(".input-unload-on-this-page").on("click change",function(e){if(b=a(this).attr("data-handle"),c=a(this).hasClass("wpacu_unload_rule_for_style")?"style":"script",a(this).prop("checked")){if("click"===e.type&&!f.triggerAlertWhenAnyUnloadRuleIsChosen(b,c))return!1;f.uncheckAllOtherBulkUnloadRules(a(this),!1),f.showHandleLoadExceptionArea(c,b),a(this).closest("tr").addClass("wpacu_not_load")}else a(this).closest("tr").removeClass("wpacu_not_load"),d=a(this).parents(".wpacu_asset_row"),f.hideHandleLoadExceptionArea(d,b,c)}),a(".wpacu-plugin-check-all").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin");a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]').find(e).prop("checked",!0).closest("tr").addClass("wpacu_not_load")}),a(".wpacu-plugin-uncheck-all").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin");a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]').find(e).prop("checked",!1).closest("tr").removeClass("wpacu_not_load")}),a(".wpacu-plugin-check-load-all").on("click change",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin"),d=a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]');d.find(".wpacu_load_it_option_one.wpacu_load_exception").prop("checked",!0).closest("tr.wpacu_is_bulk_unloaded").removeClass("wpacu_not_load"),d.find(e).prop("checked",!1).trigger("change")}),a(".wpacu-plugin-uncheck-load-all").on("click change",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-plugin"),d=a('table.wpacu_list_by_location[data-wpacu-plugin="'+c+'"]');d.find(".wpacu_load_it_option_one.wpacu_load_exception").prop("checked",!1).closest("tr.wpacu_is_bulk_unloaded").addClass("wpacu_not_load"),d.find(e).prop("checked",!1).trigger("change")}),a(".wpacu_keep_bulk_rule").click(function(){a(this).prop("checked")&&a(this).parents("li").next().removeClass("remove_rule")}),a(".wpacu_remove_bulk_rule").click(function(){a(this).prop("checked")&&a(this).parents("li").addClass("remove_rule")}),a(".wpacu_bulk_unload").on("click change",function(e){b=a(this).attr("data-handle"),c=a(this).attr("data-handle-for"),d=a("[data-"+c+'-handle-row="'+b+'"]');var g=a(this).parents("li");if(a(this).prop("checked")){if("click"===e.type&&!f.triggerAlertWhenAnyUnloadRuleIsChosen(b,c))return!1;a(this).hasClass("wpacu_unload_it_regex_checkbox")?(g.find("label").addClass("wpacu_unload_checked"),g.find("textarea").prop("disabled",!1).focus().removeClass("wpacu_disabled"),g.find(".wpacu_handle_unload_regex_input_wrap").removeClass("wpacu_hide")):(a(this).parent("label").addClass("wpacu_input_load_checked"),a(this).closest("tr").addClass("wpacu_not_load")),f.showHandleLoadExceptionArea(c,b),a(this).hasClass("wpacu_global_unload")?(f.uncheckAllOtherBulkUnloadRules(a(this),!0),a('.input-unload-on-this-page[data-handle-for="'+c+'"][data-handle="'+b+'"]').prop("checked",!1)):a(this).hasClass("wpacu_post_type_unload")&&(f.uncheckAllOtherBulkUnloadRules(a(this),!1),a('.input-unload-on-this-page[data-handle-for="'+c+'"][data-handle="'+b+'"]').prop("checked",!1))}else a(this).hasClass("wpacu_unload_it_regex_checkbox")?(g.find("label").removeClass("wpacu_unload_checked"),g.find("textarea").blur().addClass("wpacu_disabled"),""===g.find("textarea").val().trim()&&(g.find("textarea").prop("disabled",!0).val(""),g.find(".wpacu_handle_unload_regex_input_wrap").addClass("wpacu_hide"))):(a(this).parent("label").removeClass("wpacu_input_load_checked"),a(this).closest("tr").removeClass("wpacu_not_load")),f.hideHandleLoadExceptionArea(d,b,c);d.hasClass("wpacu_is_bulk_unloaded")||a(".wpacu_bulk_unload:not(.wpacu_unload_it_regex_checkbox)").is(":checked")||a(this).closest("tr").removeClass("wpacu_not_load")}),a(".wpacu_load_it_option_one.wpacu_load_exception").on("click change",function(){var b=a(this).attr("data-handle");if(a(this).prop("checked")){a(this).parent("label").addClass("wpacu_global_unload_exception");var c="";a(this).hasClass("wpacu_style")?c="style":a(this).hasClass("wpacu_script")&&(c="script"),a("#"+c+"_"+b).prop("checked",!1).trigger("change")}else a(this).parent("label").removeClass("wpacu_global_unload_exception")}),a(".wpacu_load_it_option_two").on("click change",function(){var b=a(this).parents("li");a(this).prop("checked")?(b.find("label").addClass("wpacu_bold"),b.find("textarea").prop("disabled",!1).focus().removeClass("wpacu_disabled"),b.find(".wpacu_load_regex_input_wrap").removeClass("wpacu_hide")):(b.find("label").removeClass("wpacu_bold"),b.find("textarea").blur().addClass("wpacu_disabled"),""===b.find("textarea").val().trim()&&(b.find("textarea").prop("disabled",!0).val(""),b.find(".wpacu_load_regex_input_wrap").addClass("wpacu_hide")))}),a(".wpacu_script_attr_rule_input").on("click change",function(){a(this).is(":checked")&&(a(this).parents("ul").find(".wpacu_script_attr_rule_input").not(a(this)).prop("checked",!1),a(this).hasClass("wpacu_script_attr_rule_global")&&a(this).parents("ul").find(".wpacu-script-attr-make-exception").removeClass("wpacu_hide")),a(this).parents("ul").find(".wpacu_script_attr_rule_global").is(":checked")||a(this).parents("ul").find(".wpacu-script-attr-make-exception").addClass("wpacu_hide")}),a(".wpacu-add-handle-note").on("click",function(b){b.preventDefault();var c,d,e=a(this).attr("data-handle");a(this).hasClass("wpacu-for-script")?c=a('.wpacu-handle-notes-field[data-script-handle="'+e+'"]'):a(this).hasClass("wpacu-for-style")&&(c=a('.wpacu-handle-notes-field[data-style-handle="'+e+'"]')),c.length<1||(d=c.find(":input"),c.is(":hidden")?(c.show(),d.prop("disabled",!1)):(c.hide(),""===d.val().trim()&&"true"===d.attr("data-wpacu-is-empty-on-page-load")&&d.prop("disabled",!0).val("")))}),a(".wpacu-external-file-size").on("click",function(b){b.preventDefault();var c,d=a(this),e=d.attr("data-src");d.hide(),c=d.next(),c.show(),e.includes("/?")?a.get(e,{},function(a,b,d){if("success"!==b)return"N/A";c.html(wpacuBytesToSize(a.length))}):a.post(wpacu_object.ajax_url,{action:wpacu_object.plugin_id+"_get_external_file_size",wpacu_remote_file:e},function(a){c.html(a)})}),a(".wpacu_handle_row_expand_contract").on("click",function(b){b.preventDefault();var c=a(this).attr("data-wpacu-handle"),d=a(this).attr("data-wpacu-handle-for");a(this).find("span").hasClass("dashicons-minus")?(a(this).parents("td").attr("data-wpacu-row-status","contracted").find(".wpacu_handle_row_expanded_area").addClass("wpacu_hide"),a(this).find("span").removeClass("dashicons-minus").addClass("dashicons-plus"),a("#wpacu_"+d+"_"+c+"_row_contracted_area").val("1")):a(this).find("span").hasClass("dashicons-plus")&&(a(this).parents("td").attr("data-wpacu-row-status","expanded").find(".wpacu_handle_row_expanded_area").removeClass("wpacu_hide"),a(this).find("span").removeClass("dashicons-plus").addClass("dashicons-minus"),a("#wpacu_"+d+"_"+c+"_row_contracted_area").val(""))});a('[data-is-hardcoded-asset="true"]').length>0&&(a.each(a('[data-is-hardcoded-asset="true"]'),function(b,c){f.updateHardcodedDataHiddenFieldStatus(a(this))}),a('[data-is-hardcoded-asset="true"]').on("click",".wpacu_unload_rule_input",function(){f.updateHardcodedDataHiddenFieldStatus(a(this).parents("[data-is-hardcoded-asset]"))}))},updateHardcodedDataHiddenFieldStatus:function(b){var c=!1;b.is("[data-style-handle-row]")?c=b.attr("data-style-handle-row"):b.is("[data-script-handle-row]")&&(c=b.attr("data-script-handle-row")),c&&(b.find(".wpacu_unload_rule_input:checked").length>0||b.hasClass("wpacu_not_load")?a("#"+c+"_hardcoded_data").prop("disabled",!1):a("#"+c+"_hardcoded_data").prop("disabled",!0))},triggerAlertWhenAnyUnloadRuleIsChosen:function(b,c){if("dashicons"===b&&"style"===c&&a('input[name="wpacu_ignore_child[styles][nf-display]').length>0&&!confirm(wpacu_object.dashicons_unload_alert_ninja_forms))return!1;if("script"===c){if(("jquery"===b||"jquery-core"===b)&&a("#script_jquery_ignore_children").length>0&&!confirm(wpacu_object.jquery_unload_alert))return!1;if(("backbone"===b||"underscore"===b)&&!confirm(wpacu_object.sensitive_library_unload_alert))return!1}return!0},pluginLoadManager:function(){a(".wpacu_plugin_load_it").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")&&(f.hidePluginLoadExceptionArea(b),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),a('.wpacu_plugin_unload_site_wide[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_radio[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"))}),a(".wpacu_plugin_unload_site_wide").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?(a(this).parent("label").addClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_radio[data-wpacu-plugin-path="'+b+'"]').parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),f.showPluginLoadExceptionArea(b)):(a(this).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!0))}),a(".wpacu_plugin_unload_regex_radio").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?(a(this).parent("label").addClass("wpacu_plugin_unload_rule_input_checked"),a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide"),f.showPluginLoadExceptionArea(b),a('.wpacu_plugin_unload_site_wide[data-wpacu-plugin-path="'+b+'"]').prop("checked",!1).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked")):(a('.wpacu_plugin_unload_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"),a(this).parent("label").removeClass("wpacu_plugin_unload_rule_input_checked"),a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide"))}),a(".wpacu_plugin_load_exception_regex").on("click",function(){var b=a(this).attr("data-wpacu-plugin-path");a(this).prop("checked")?a('.wpacu_load_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide"):a('.wpacu_load_regex_input_wrap[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide")})},showPluginLoadExceptionArea:function(b){a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').removeClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!1)},hidePluginLoadExceptionArea:function(b){a('.wrap_plugin_load_exception_options[data-wpacu-plugin-path="'+b+'"]').addClass("wpacu_hide").find('input[type="checkbox"]').prop("disabled",!0)},showHandleLoadExceptionArea:function(b,c){var d=a("div.wpacu_exception_options_area_wrap[data-"+b+'-handle="'+c+'"]');d.parent("div").removeClass("wpacu_hide"),d.find('input[type="checkbox"]').prop("disabled",!1)},hideHandleLoadExceptionArea:function(b,c,d){if(!b.hasClass("wpacu_is_bulk_unloaded")&&!b.find(".wpacu_bulk_unload").is(":checked")){var e=a("div.wpacu_exception_options_area_wrap[data-"+d+'-handle="'+c+'"]');e.parent("div").addClass("wpacu_hide"),e.find('input[type="checkbox"]').prop("disabled",!0)}},uncheckAllOtherBulkUnloadRules:function(a,b){var c=".wpacu_bulk_unload";!1===b&&(c=".wpacu_bulk_unload:not(.wpacu_unload_it_regex_checkbox)"),a.closest("tr").find(c).not(a).prop("checked",!1).parent("label").removeClass("wpacu_input_load_checked").removeClass("wpacu_unload_checked")},checkSourcesFor404Errors:function(){var b=a("[data-wpacu-external-source]");if(!(b.length<1)){var c=b.length,d="";b.each(function(b){var e=a(this),f=e.attr("data-wpacu-external-source");d+=f+"-at-wpacu-at-",b===c-1&&jQuery.post(wpacu_object.ajax_url+"?wpacu_check_external_url",{action:wpacu_object.plugin_id+"_check_external_urls_for_status_code",wpacu_check_urls:d},function(b){var c=jQuery.parseJSON(b);a.each(c,function(b,c){a('[data-wpacu-external-source="'+c+'"]').css({color:"#cc0000"}).parent("div").find("[data-wpacu-external-source-status]").html('<small>* <em style="font-weight: 600;">'+wpacu_object.source_load_error_msg+"</em></small>")})})})}}};a(window).load(function(){f.checkSourcesFor404Errors()}),a("#wpacu_post_type_select").change(function(){a("#wpacu_post_type_form").submit()}),a("#wpacu_taxonomy_select").change(function(){a("#wpacu_taxonomy_form").submit()}),a("#wpacu_dashboard").click(function(){a(this).prop("checked")?a("#wpacu-settings-assets-retrieval-mode").show():a("#wpacu-settings-assets-retrieval-mode").hide()}),a(".wpacu-dom-get-type-selection").change(function(){a(this).is(":checked")&&(a(".wpacu-dom-get-type-info").hide(),a("#"+a(this).attr("data-target")).fadeIn("fast"))}),a("#wpacu_frontend").click(function(){a(this).prop("checked")?a("#wpacu-settings-frontend-exceptions").show():a("#wpacu-settings-frontend-exceptions").hide()}),a(".google_fonts_combine_type").change(function(){a(".wpacu_google_fonts_combine_type_area").hide(),"async"===a(this).val()?a("#wpacu_google_fonts_combine_type_async_info_area").fadeIn():"async_preload"===a(this).val()?a("#wpacu_google_fonts_combine_type_async_preload_info_area").fadeIn():a("#wpacu_google_fonts_combine_type_rb_info_area").fadeIn()}),a("#wpacu_assets_list_layout").on("click change",function(){"by-location"===a(this).val()?a("#wpacu-assets-list-by-location-selected").fadeIn("fast"):a("#wpacu-assets-list-by-location-selected").fadeOut("fast")}),a("#wpacu_disable_jquery_migrate").on("click",function(){return!a(this).is(":checked")||(!(!a(this).is(":checked")||!confirm(wpacu_object.jquery_migration_disable_confirm_msg))||(a(this).prop("checked",!1),!1))}),a("#wpacu_disable_comment_reply").on("click",function(){return!a(this).is(":checked")||(!(!a(this).is(":checked")||!confirm(wpacu_object.comment_reply_disable_confirm_msg))||(a(this).prop("checked",!1),!1))}),a("[data-target-opacity]").on("click change tick",function(){a(this).prop("checked")?a("#"+a(this).attr("data-target-opacity")).css({opacity:1}):a("#"+a(this).attr("data-target-opacity")).css({opacity:.4})}),a(".wpacu-combine-loaded-js-level").change(function(){a(this).is(":checked")&&(a(".wpacu_combine_loaded_js_level_area").removeClass("wpacu_active"),a("#"+a(this).attr("data-target")).addClass("wpacu_active"))});var g=a('#wpacu-update-button-area input[type="submit"]');g.parents("form").submit(function(){g.attr("disabled",!0),a("#wpacu-updating-settings").show()});var h=a("#wpacu-update-front-settings-area .wpacu_update_btn");if(h.parents("form").submit(function(){return h.attr("disabled",!0).addClass("wpacu_submitting"),a("#wpacu-updating-front-settings").show(),!0}),a("form#wpacu-settings-form, form#wpacu_home_page_form").submit(function(){return g.attr("disabled",!0),!0}),a(".wpacu_bulk_rule_checkbox, .wpacu_remove_preload").click(function(){var b=a(this).parents(".wpacu_bulk_change_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a(".wpacu_remove_regex").click(function(){var b=a(this).parents(".wpacu_regex_rule_row");a(this).prop("checked")?b.addClass("wpacu_enabled"):b.removeClass("wpacu_enabled")}),a(".wpacu_restore_position").click(function(){var b=a(this).parents(".wpacu_restore_position_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a(".wpacu_remove_global_attr").click(function(){var b=a(this).parents(".wpacu_remove_global_attr_row");a(this).prop("checked")?b.addClass("wpacu_selected"):b.removeClass("wpacu_selected")}),a("#wpacu_wrap_assets").length>0&&setTimeout(function(){f.load()},200),a("#wpacu-plugins-load-manager-wrap").length>0&&setTimeout(function(){f.pluginLoadManager()},200),"undefined"==typeof wpacu_object||a("#wpacu_meta_box_content").length<1)return!1;("default"===wpacu_object.list_show_status||""===wpacu_object.list_show_status||wpacu_object.override_assets_list_load)&&b(),"fetch_on_click"===wpacu_object.list_show_status&&a("#wpacu_ajax_fetch_on_click_btn").click(function(c){c.preventDefault(),a(this).hide(),a("#wpacu_fetching_assets_list_wrap").show(),b()}),a(document).on("click",".wp-admin.post-php .edit-post-header__settings button.is-primary",function(){var c=function(){if(0===a(".edit-post-header__settings .is-saving").length){if(a("#wpacu_unload_assets_area_loaded").length>0&&a("#wpacu_unload_assets_area_loaded").val()){a("#wpacu-assets-reloading").remove();var c='<span id="wpacu-assets-reloading" class="editor-post-saved-state is-wpacu-reloading">'+wpacu_object.reload_icon+wpacu_object.reload_msg+"</span>";a(".wp-admin.post-php .edit-post-header__settings").prepend(c)}a(".wpacu_asset_row").addClass("wpacu-loading"),b(),wpacuAjaxClearCache(),clearInterval(d)}},d=setInterval(c,900)})}),""!==wpacu_object.clear_cache_on_page_load&&wpacuAjaxClearCache(),""!==wpacu_object.clear_other_caches&&setTimeout(function(){wpacuClearAutoptimizeCache()},150),jQuery(document).ready(function(a){try{var b;a('input[type="hidden"][name="_wp_http_referer"]').length>0&&(b=a('input[type="hidden"][name="_wp_http_referer"]').val(),b.includes("term.php?taxonomy=")&&b.includes("message=")&&wpacuAjaxClearCache(),b.includes("post.php?post=")&&b.includes("message=")&&wpacuAjaxClearCache())}catch(a){console.log(a)}});
classes/CleanUp.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
 
 
4
  /**
5
  * Class CleanUp
6
  * @package WpAssetCleanUp
@@ -23,7 +25,7 @@ class CleanUp
23
  */
24
  public function doClean()
25
  {
26
- if (Main::instance()->preventAssetsSettings()) {
27
  return;
28
  }
29
 
@@ -45,6 +47,10 @@ class CleanUp
45
  if ($settings['remove_rest_api_link'] == 1) {
46
  // <link rel='https://api.w.org/' href='https://yourwebsite.com/wp-json/' />
47
  remove_action('wp_head', 'rest_output_link_wp_head');
 
 
 
 
48
  }
49
 
50
  // Remove "Shortlink"?
@@ -54,8 +60,7 @@ class CleanUp
54
 
55
  // link: <https://yourdomainname.com/wp-json/>; rel="https://api.w.org/", <https://yourdomainname.com/?p=[post_id_here]>; rel=shortlink
56
  remove_action('template_redirect', 'wp_shortlink_header', 11);
57
-
58
- }
59
 
60
  // Remove "Post's Relational Links"?
61
  if ($settings['remove_posts_rel_links'] == 1) {
@@ -143,105 +148,128 @@ class CleanUp
143
  */
144
  public static function removeMetaGenerators($htmlSource)
145
  {
146
- if (stripos($htmlSource, '<meta') === false) {
147
- return $htmlSource;
148
- }
 
 
 
 
 
 
149
 
150
- // Use DOMDocument to alter the HTML Source and Remove the tags
151
- $htmlSourceOriginal = $htmlSource;
 
 
 
 
152
 
153
- if (function_exists('libxml_use_internal_errors')
154
- && function_exists('libxml_clear_errors')
155
- && class_exists('DOMDocument'))
156
- {
157
- $document = new \DOMDocument();
158
- libxml_use_internal_errors(true);
159
 
160
- $document->loadHTML($htmlSource);
 
 
161
 
162
- $domUpdated = false;
163
 
164
- foreach ($document->getElementsByTagName('meta') as $tagObject) {
165
- $nameAttrValue = $tagObject->getAttribute('name');
 
 
 
166
 
167
- if ($nameAttrValue === 'generator') {
168
- $outerTag = $outerTagRegExp = trim(self::getOuterHTML($tagObject));
 
169
 
170
- // As DOMDocument doesn't retrieve the exact string, some alterations to the RegEx have to be made
171
- // Leave no room for errors as all sort of characters can be within the "content" attribute
172
- $last2Chars = substr($outerTag, -2);
 
 
 
173
 
174
- if ($last2Chars === '">' || $last2Chars === "'>") {
175
- $tagWithoutLastChar = substr($outerTag, 0, -1);
176
- $outerTagRegExp = preg_quote($tagWithoutLastChar, '/').'(.*?)>';
177
- }
178
 
179
- $outerTagRegExp = str_replace(
180
- array('"', '&lt;', '&gt;'),
181
- array('(["\'])', '(<|&lt;)', '(>|&gt;)'),
182
- $outerTagRegExp
183
- );
 
 
184
 
185
- if (strpos($outerTagRegExp, '<meta') !== false) {
186
- preg_match_all('#' . $outerTagRegExp . '#si', $htmlSource, $matches);
 
187
 
188
- if (isset($matches[0][0]) && ! empty($matches[0][0]) && strip_tags($matches[0][0]) === '') {
189
- $htmlSource = str_replace( $matches[0][0], '', $htmlSource );
 
190
  }
191
 
192
- if ($htmlSource !== $htmlSourceOriginal) {
193
- $domUpdated = true;
 
 
 
 
 
 
 
 
 
 
194
  }
195
  }
196
  }
197
- }
198
-
199
- libxml_clear_errors();
200
-
201
- if ($domUpdated) {
202
- return $htmlSource;
203
- }
204
- }
205
 
206
- // DOMDocument is not enabled. Use the RegExp instead (not as smooth, but does its job)!
207
- preg_match_all('#<meta[^>]*name(\s+|)=(\s+|)("|\')generator("|\').*("|\'|\/)(\s+|)>#Usmi', $htmlSource, $matches);
208
 
209
- if (isset($matches[0]) && ! empty($matches[0])) {
210
- foreach ($matches[0] as $metaTag) {
211
- if (strip_tags($metaTag) === '') { // make sure the full tag was extracted
212
- $htmlSource = str_replace($metaTag, '', $htmlSource);
213
- }
214
  }
215
  }
216
 
 
 
 
217
  return $htmlSource;
218
  }
219
 
220
  /**
221
  * @param $htmlSource
 
 
222
  *
223
- * @return mixed
224
  */
225
- public static function removeHtmlComments($htmlSource)
226
  {
227
  // No comments? Do not continue
228
  if (strpos($htmlSource, '<!--') === false) {
229
  return $htmlSource;
230
  }
231
 
232
- if (! (function_exists('libxml_use_internal_errors')
233
- && function_exists('libxml_clear_errors')
234
- && class_exists('DOMDocument')))
235
- {
236
  return $htmlSource;
237
  }
238
 
239
- $domComments = new \DOMDocument();
240
- libxml_use_internal_errors(true);
 
 
 
 
 
 
 
241
 
242
- $domComments->loadHTML($htmlSource);
 
 
243
 
244
- $xpathComments = new \DOMXPath($domComments);
245
  $comments = $xpathComments->query('//comment()');
246
 
247
  libxml_clear_errors();
@@ -278,18 +306,21 @@ class CleanUp
278
  }
279
  }
280
 
 
 
281
  foreach ($comments as $comment) {
282
- $entireComment = self::getOuterHTML($comment);
283
 
284
  // Do not strip MSIE conditional comments
285
- if (strpos($entireComment, '<!--<![endif]-->') !== false ||
286
- preg_match('#<!--\[if(.*?)]>(.*?)<!-->#si', $entireComment) ||
287
- preg_match('#<!--\[if(.*?)\[endif]-->#si', $entireComment)) {
288
  continue;
289
  }
290
 
291
  // Any exceptions set in "Strip HTML comments?" textarea?
292
- if (Main::instance()->settings['remove_html_comments_exceptions']) {
 
293
  $removeHtmlCommentsExceptions = trim(Main::instance()->settings['remove_html_comments_exceptions']);
294
 
295
  if (strpos($removeHtmlCommentsExceptions, "\n") !== false) {
@@ -305,14 +336,15 @@ class CleanUp
305
  }
306
  }
307
 
308
- $htmlSource = str_replace(
309
- array(
310
- $entireComment,
311
- '<!--' . $comment->nodeValue . '-->'
312
- ),
313
- '',
314
- $htmlSource
315
- );
 
316
  }
317
 
318
  if (! empty($commentsWithinQuotes)) {
@@ -332,7 +364,6 @@ class CleanUp
332
  public static function getOuterHTML($e)
333
  {
334
  $doc = new \DOMDocument();
335
-
336
  libxml_use_internal_errors( true );
337
 
338
  $doc->appendChild($doc->importNode($e, true));
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
4
+ use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
5
+
6
  /**
7
  * Class CleanUp
8
  * @package WpAssetCleanUp
25
  */
26
  public function doClean()
27
  {
28
+ if (Plugin::preventAnyChanges() || Main::instance()->preventAssetsSettings()) {
29
  return;
30
  }
31
 
47
  if ($settings['remove_rest_api_link'] == 1) {
48
  // <link rel='https://api.w.org/' href='https://yourwebsite.com/wp-json/' />
49
  remove_action('wp_head', 'rest_output_link_wp_head');
50
+
51
+ // Removes the following printed within "Response headers":
52
+ // <https://yourwebsite.com/wp-json/>; rel="https://api.w.org/"
53
+ remove_action( 'template_redirect', 'rest_output_link_header', 11 );
54
  }
55
 
56
  // Remove "Shortlink"?
60
 
61
  // link: <https://yourdomainname.com/wp-json/>; rel="https://api.w.org/", <https://yourdomainname.com/?p=[post_id_here]>; rel=shortlink
62
  remove_action('template_redirect', 'wp_shortlink_header', 11);
63
+ }
 
64
 
65
  // Remove "Post's Relational Links"?
66
  if ($settings['remove_posts_rel_links'] == 1) {
148
  */
149
  public static function removeMetaGenerators($htmlSource)
150
  {
151
+ $fetchMethod = 'dom'; // 'regex' or 'dom'
152
+
153
+ if ($fetchMethod === 'regex') {
154
+ preg_match_all(
155
+ '/<meta.*name=(|\'|")generator(\\1).*content=(|\'|")(.*?)(|\'|").*?>/i',
156
+ $htmlSource,
157
+ $matchesSourcesFromTags,
158
+ PREG_SET_ORDER
159
+ );
160
 
161
+ preg_match_all(
162
+ '/<meta.*content=(|\'|")(.*?)(\\1).*name=(|\'|")generator(\\2).*?>/i',
163
+ $htmlSource,
164
+ $matchesSourcesFromTagsTwo,
165
+ PREG_SET_ORDER
166
+ );
167
 
168
+ $matchesSourcesFromTags = array_merge($matchesSourcesFromTags, $matchesSourcesFromTagsTwo);
 
 
 
 
 
169
 
170
+ if (empty($matchesSourcesFromTags)) {
171
+ return $htmlSource;
172
+ }
173
 
174
+ $metaTagsToStrip = array();
175
 
176
+ foreach ($matchesSourcesFromTags as $matchesResults) {
177
+ if (isset($matchesResults[0]) && ($matchedTag = $matchesResults[0])) {
178
+ if (strip_tags($matchedTag) !== '') { // Needs to be a proper match (very rare cases, but it can happen)
179
+ continue;
180
+ }
181
 
182
+ $metaTagsToStrip[$matchedTag] = '';
183
+ }
184
+ }
185
 
186
+ $htmlSource = strtr($htmlSource, $metaTagsToStrip);
187
+ } elseif ($fetchMethod === 'dom') {
188
+ if ( function_exists( 'libxml_use_internal_errors' ) && function_exists( 'libxml_clear_errors' ) && class_exists( '\DOMDocument' ) ) {
189
+ if ($htmlSource === '') {
190
+ return $htmlSource;
191
+ }
192
 
193
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'removeMetaGenerators');
 
 
 
194
 
195
+ $metaTagsToStrip = array();
196
+
197
+ foreach ( $domTag->getElementsByTagName( 'meta' ) as $tagObject ) {
198
+ $nameAttrValue = $tagObject->getAttribute( 'name' );
199
+
200
+ if ( $nameAttrValue === 'generator' ) {
201
+ $outerTag = $outerTagRegExp = trim( self::getOuterHTML( $tagObject ) );
202
 
203
+ // As DOMDocument doesn't retrieve the exact string, some alterations to the RegEx have to be made
204
+ // Leave no room for errors as all sort of characters can be within the "content" attribute
205
+ $last2Chars = substr( $outerTag, - 2 );
206
 
207
+ if ( $last2Chars === '">' || $last2Chars === "'>" ) {
208
+ $tagWithoutLastChar = substr( $outerTag, 0, - 1 );
209
+ $outerTagRegExp = preg_quote( $tagWithoutLastChar, '/' ) . '(.*?)>';
210
  }
211
 
212
+ $outerTagRegExp = str_replace(
213
+ array( '"', '&lt;', '&gt;' ),
214
+ array( '("|\'|)', '(<|&lt;)', '(>|&gt;)' ),
215
+ $outerTagRegExp
216
+ );
217
+
218
+ if ( strpos( $outerTagRegExp, '<meta' ) !== false ) {
219
+ preg_match_all( '#' . $outerTagRegExp . '#si', $htmlSource, $matches );
220
+
221
+ if ( isset( $matches[0][0] ) && ! empty( $matches[0][0] ) && strip_tags( $matches[0][0] ) === '' ) {
222
+ $metaTagsToStrip[$matches[0][0]] = '';
223
+ }
224
  }
225
  }
226
  }
 
 
 
 
 
 
 
 
227
 
228
+ $htmlSource = strtr($htmlSource, $metaTagsToStrip);
 
229
 
230
+ libxml_clear_errors();
 
 
 
 
231
  }
232
  }
233
 
234
+ /* [wpacu_timing] */
235
+ Misc::scriptExecTimer( 'alter_html_source_for_remove_meta_generators',
236
+ 'end' ); /* [/wpacu_timing] */
237
  return $htmlSource;
238
  }
239
 
240
  /**
241
  * @param $htmlSource
242
+ * @param bool $ignoreExceptions
243
+ * @param $for
244
  *
245
+ * @return string|string[]
246
  */
247
+ public static function removeHtmlComments($htmlSource, $ignoreExceptions = false, $for = 'cleaner_dom_to_fetch')
248
  {
249
  // No comments? Do not continue
250
  if (strpos($htmlSource, '<!--') === false) {
251
  return $htmlSource;
252
  }
253
 
254
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument'))) {
 
 
 
255
  return $htmlSource;
256
  }
257
 
258
+ $domTag = '';
259
+
260
+ if ($for === 'cleaner_dom_to_fetch') {
261
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'removeHtmlComments');
262
+ }
263
+
264
+ if ($for === 'final_output') {
265
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'removeHtmlCommentsFinal');
266
+ }
267
 
268
+ if (! $domTag) {
269
+ return $htmlSource;
270
+ }
271
 
272
+ $xpathComments = new \DOMXPath($domTag);
273
  $comments = $xpathComments->query('//comment()');
274
 
275
  libxml_clear_errors();
306
  }
307
  }
308
 
309
+ $stripCommentsList = array();
310
+
311
  foreach ($comments as $comment) {
312
+ $entireComment = '<!--' . $comment->nodeValue . '-->';
313
 
314
  // Do not strip MSIE conditional comments
315
+ if ( strpos( $entireComment, '<!--<![endif]-->' ) !== false ||
316
+ preg_match( '#<!--\[if(.*?)]>(.*?)<!-->#si', $entireComment ) ||
317
+ preg_match( '#<!--\[if(.*?)\[endif]-->#si', $entireComment ) ) {
318
  continue;
319
  }
320
 
321
  // Any exceptions set in "Strip HTML comments?" textarea?
322
+ // $ignoreExceptions has to be set to false (as it is by default)
323
+ if (! $ignoreExceptions && Main::instance()->settings['remove_html_comments_exceptions']) {
324
  $removeHtmlCommentsExceptions = trim(Main::instance()->settings['remove_html_comments_exceptions']);
325
 
326
  if (strpos($removeHtmlCommentsExceptions, "\n") !== false) {
336
  }
337
  }
338
 
339
+ if (strlen($entireComment) < 200) {
340
+ $stripCommentsList[ $entireComment ] = '';
341
+ } else {
342
+ $htmlSource = str_replace($entireComment, '', $htmlSource);
343
+ }
344
+ }
345
+
346
+ if (! empty($stripCommentsList)) {
347
+ $htmlSource = strtr( $htmlSource, $stripCommentsList );
348
  }
349
 
350
  if (! empty($commentsWithinQuotes)) {
364
  public static function getOuterHTML($e)
365
  {
366
  $doc = new \DOMDocument();
 
367
  libxml_use_internal_errors( true );
368
 
369
  $doc->appendChild($doc->importNode($e, true));
classes/Debug.php CHANGED
@@ -18,11 +18,13 @@ class Debug
18
  add_action('wp_footer', array($this, 'showDebugOptions'), PHP_INT_MAX);
19
  }
20
 
21
- add_action('wp', static function() {
22
- if ( isset( $_GET['wpacu_get_cache_dir_size'] ) && Menu::userCanManageAssets() ) { // Only print within the Dashboard
23
- self::printCacheDirInfo();
24
- }
25
- });
 
 
26
  }
27
 
28
  /**
@@ -178,9 +180,7 @@ class Debug
178
  <li>From CSS file to Inline: {wpacu_alter_html_source_for_inline_css_exec_time}</li>
179
  <li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_css_exec_time}</li>
180
  <li>Preloads: {wpacu_alter_html_source_for_preload_css_exec_time}</li>
181
- <!-- removeIf(development) -->
182
- <!--<li>Dynamic Loaded CSS (if any): {wpacu_alter_html_source_for_dynamic_loaded_css_exec_time}</li>-->
183
- <!-- endRemoveIf(development) -->
184
  <li>Combine: {wpacu_alter_html_source_for_combine_css_exec_time}</li>
185
  <li>Minify Inline Tags: {wpacu_alter_html_source_for_minify_inline_style_tags_exec_time}</li>
186
  <li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_css_exec_time}</li>
@@ -191,9 +191,7 @@ class Debug
191
  <ul>
192
  <li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_js_exec_time}</li>
193
  <li>Preloads: {wpacu_alter_html_source_for_preload_js_exec_time}</li>
194
- <!-- removeIf(development) -->
195
- <!--<li>Dynamic Loaded JS (if any): {wpacu_alter_html_source_for_dynamic_loaded_js_exec_time}</li>-->
196
- <!-- endRemoveIf(development) -->
197
  <li>Combine: {wpacu_alter_html_source_for_combine_js_exec_time}</li>
198
  <li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_js_exec_time}</li>
199
  <li>Move any inline wih jQuery code after jQuery library: {wpacu_alter_html_source_move_inline_jquery_after_src_tag_exec_time}</li>
18
  add_action('wp_footer', array($this, 'showDebugOptions'), PHP_INT_MAX);
19
  }
20
 
21
+ foreach(array('wp', 'admin_init') as $wpacuActionHook) {
22
+ add_action( $wpacuActionHook, static function() {
23
+ if ( isset( $_GET['wpacu_get_cache_dir_size'] ) && Menu::userCanManageAssets() ) {
24
+ self::printCacheDirInfo();
25
+ }
26
+ });
27
+ }
28
  }
29
 
30
  /**
180
  <li>From CSS file to Inline: {wpacu_alter_html_source_for_inline_css_exec_time}</li>
181
  <li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_css_exec_time}</li>
182
  <li>Preloads: {wpacu_alter_html_source_for_preload_css_exec_time}</li>
183
+ <!-- -->
 
 
184
  <li>Combine: {wpacu_alter_html_source_for_combine_css_exec_time}</li>
185
  <li>Minify Inline Tags: {wpacu_alter_html_source_for_minify_inline_style_tags_exec_time}</li>
186
  <li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_css_exec_time}</li>
191
  <ul>
192
  <li>Update Original to Optimized: {wpacu_alter_html_source_original_to_optimized_js_exec_time}</li>
193
  <li>Preloads: {wpacu_alter_html_source_for_preload_js_exec_time}</li>
194
+ <!-- -->
 
 
195
  <li>Combine: {wpacu_alter_html_source_for_combine_js_exec_time}</li>
196
  <li>Unload (ignore dependencies): {wpacu_alter_html_source_unload_ignore_deps_js_exec_time}</li>
197
  <li>Move any inline wih jQuery code after jQuery library: {wpacu_alter_html_source_move_inline_jquery_after_src_tag_exec_time}</li>
classes/HardcodedAssets.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
4
- use WpAssetCleanUp\OptimiseAssets\MinifyJs;
5
  use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
6
  use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
7
 
@@ -83,7 +82,7 @@ class HardcodedAssets
83
  */
84
  public static function addHardcodedAssetsForEditFrontEndView($htmlSource)
85
  {
86
- if ( ! ($anyHardCodedAssets = wp_cache_get('wpacu_hardcoded_assets_encoded')) ) {
87
  $htmlSource = str_replace( '{wpacu_assets_collapsible_wrap_hardcoded_list}', '', $htmlSource);
88
  return $htmlSource;
89
  }
@@ -91,7 +90,7 @@ class HardcodedAssets
91
  $jsonH = base64_decode($anyHardCodedAssets);
92
 
93
  $wpacuPrintHardcodedManagementList = static function($jsonH) {
94
- $data = wp_cache_get('wpacu_settings_frontend_data') ?: array();
95
  $data['do_not_print_list'] = true;
96
  $data['all']['hardcoded'] = (array)json_decode($jsonH, ARRAY_A);
97
  ob_start();
@@ -126,7 +125,7 @@ class HardcodedAssets
126
  */
127
  public static function getAll($htmlSource, $encodeIt = true)
128
  {
129
- $htmlSourceAlt = self::removeHtmlCommentsExceptMSIE($htmlSource);
130
 
131
  $collectLinkStyles = true; // default
132
  $collectScripts = true; // default
@@ -140,7 +139,6 @@ class HardcodedAssets
140
  /*
141
  * [START] Collect Hardcoded LINK (stylesheet) & STYLE tags
142
  */
143
- // Extract all the LINK tag that do not have "data-wpacu-debug-style-handle="
144
  preg_match_all( '#(?=(?P<link_tag><link[^>]*stylesheet[^>]*(>)))|(?=(?P<style_tag><style[^>]*?>.*</style>))#Umsi',
145
  $htmlSourceAlt, $matchesSourcesFromTags, PREG_SET_ORDER );
146
 
@@ -246,7 +244,6 @@ class HardcodedAssets
246
  }
247
 
248
  $allInlineAssocWithJsHandle = array_unique($allInlineAssocWithJsHandle);
249
-
250
  }
251
 
252
  // Go through the hardcoded SCRIPT tags
@@ -370,7 +367,7 @@ class HardcodedAssets
370
 
371
  if (self::useBufferingForEditFrontEndView()) {
372
  // Triggered within the front-end view (when admin is logged-in and manages the assets)
373
- wp_cache_set( 'wpacu_hardcoded_content_within_conditional_comments', $tagsWithinConditionalComments );
374
  } elseif (Main::instance()->isGetAssetsCall) {
375
  // AJAX call within the Dashboard
376
  $hardCodedAssets['within_conditional_comments'] = $tagsWithinConditionalComments;
@@ -388,6 +385,7 @@ class HardcodedAssets
388
  *
389
  * @return mixed
390
  */
 
391
  public static function removeHtmlCommentsExceptMSIE($htmlSource)
392
  {
393
  // No comments? Do not continue
@@ -395,29 +393,28 @@ class HardcodedAssets
395
  return $htmlSource;
396
  }
397
 
398
- if (! (function_exists('libxml_use_internal_errors')
399
- && function_exists('libxml_clear_errors')
400
- && class_exists('DOMDocument')))
401
- {
402
  return $htmlSource;
403
  }
404
 
405
- $domComments = new \DOMDocument();
406
- libxml_use_internal_errors(true);
407
-
408
  preg_match_all('#<!--\[if(.*?)]>(<!-->|-->|\s|)(.*?)(<!--<!|<!)\[endif]-->#si', $htmlSource, $matchedMSIEComments);
409
 
410
- $htmlSourceAlt = $htmlSource;
411
 
412
  if (isset($matchedMSIEComments[0]) && ! empty($matchedMSIEComments[0])) {
413
  foreach ($matchedMSIEComments[0] as $matchedMSIEComment) {
414
- $htmlSourceAlt = str_replace($matchedMSIEComment, '', $htmlSourceAlt);
415
  }
416
  }
417
 
418
- $domComments->loadHTML($htmlSourceAlt); // fetch from the altered HTML (without the MSIE comments)
 
 
 
 
419
 
420
- $xpathComments = new \DOMXPath($domComments);
421
  $comments = $xpathComments->query('//comment()');
422
 
423
  libxml_clear_errors();
@@ -475,6 +472,8 @@ class HardcodedAssets
475
 
476
  return $htmlSource;
477
  }
 
 
478
 
479
  /**
480
  * @param $htmlSource
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
 
4
  use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
5
  use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
6
 
82
  */
83
  public static function addHardcodedAssetsForEditFrontEndView($htmlSource)
84
  {
85
+ if ( ! ($anyHardCodedAssets = ObjectCache::wpacu_cache_get('wpacu_hardcoded_assets_encoded')) ) {
86
  $htmlSource = str_replace( '{wpacu_assets_collapsible_wrap_hardcoded_list}', '', $htmlSource);
87
  return $htmlSource;
88
  }
90
  $jsonH = base64_decode($anyHardCodedAssets);
91
 
92
  $wpacuPrintHardcodedManagementList = static function($jsonH) {
93
+ $data = ObjectCache::wpacu_cache_get('wpacu_settings_frontend_data') ?: array();
94
  $data['do_not_print_list'] = true;
95
  $data['all']['hardcoded'] = (array)json_decode($jsonH, ARRAY_A);
96
  ob_start();
125
  */
126
  public static function getAll($htmlSource, $encodeIt = true)
127
  {
128
+ $htmlSourceAlt = CleanUp::removeHtmlComments($htmlSource, true);
129
 
130
  $collectLinkStyles = true; // default
131
  $collectScripts = true; // default
139
  /*
140
  * [START] Collect Hardcoded LINK (stylesheet) & STYLE tags
141
  */
 
142
  preg_match_all( '#(?=(?P<link_tag><link[^>]*stylesheet[^>]*(>)))|(?=(?P<style_tag><style[^>]*?>.*</style>))#Umsi',
143
  $htmlSourceAlt, $matchesSourcesFromTags, PREG_SET_ORDER );
144
 
244
  }
245
 
246
  $allInlineAssocWithJsHandle = array_unique($allInlineAssocWithJsHandle);
 
247
  }
248
 
249
  // Go through the hardcoded SCRIPT tags
367
 
368
  if (self::useBufferingForEditFrontEndView()) {
369
  // Triggered within the front-end view (when admin is logged-in and manages the assets)
370
+ ObjectCache::wpacu_cache_set( 'wpacu_hardcoded_content_within_conditional_comments', $tagsWithinConditionalComments );
371
  } elseif (Main::instance()->isGetAssetsCall) {
372
  // AJAX call within the Dashboard
373
  $hardCodedAssets['within_conditional_comments'] = $tagsWithinConditionalComments;
385
  *
386
  * @return mixed
387
  */
388
+ /*
389
  public static function removeHtmlCommentsExceptMSIE($htmlSource)
390
  {
391
  // No comments? Do not continue
393
  return $htmlSource;
394
  }
395
 
396
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument'))) {
 
 
 
397
  return $htmlSource;
398
  }
399
 
400
+ // First, collect all MSIE comments
 
 
401
  preg_match_all('#<!--\[if(.*?)]>(<!-->|-->|\s|)(.*?)(<!--<!|<!)\[endif]-->#si', $htmlSource, $matchedMSIEComments);
402
 
403
+ $allMSIEComments = array();
404
 
405
  if (isset($matchedMSIEComments[0]) && ! empty($matchedMSIEComments[0])) {
406
  foreach ($matchedMSIEComments[0] as $matchedMSIEComment) {
407
+ $allMSIEComments[] = $matchedMSIEComment;
408
  }
409
  }
410
 
411
+ if (! ($domTag = ObjectCache::wpacu_cache_get('wpacu_html_dom_tag'))) {
412
+ $domTag = new \DOMDocument();
413
+ libxml_use_internal_errors( true );
414
+ $domTag->loadHTML( $htmlSource );
415
+ }
416
 
417
+ $xpathComments = new \DOMXPath($domTag);
418
  $comments = $xpathComments->query('//comment()');
419
 
420
  libxml_clear_errors();
472
 
473
  return $htmlSource;
474
  }
475
+ */
476
+ //endRemoveIf(development)
477
 
478
  /**
479
  * @param $htmlSource
classes/ImportExport.php CHANGED
@@ -265,7 +265,7 @@ SQL;
265
 
266
  if (! empty($importedList)) {
267
  // After import was completed, clear all CSS/JS cache
268
- OptimizeCommon::clearAllCache();
269
 
270
  set_transient('wpacu_import_done', json_encode($importedList), 30);
271
 
265
 
266
  if (! empty($importedList)) {
267
  // After import was completed, clear all CSS/JS cache
268
+ OptimizeCommon::clearCache();
269
 
270
  set_transient('wpacu_import_done', json_encode($importedList), 30);
271
 
classes/Main.php CHANGED
@@ -258,7 +258,7 @@ class Main
258
  // "Direct" AJAX call or "WP Remote Post" method used?
259
  // Do not trigger the admin bar as it's not relevant
260
  if ($this->isAjaxCall || $this->isGetAssetsCall) {
261
- Misc::noAdminBarLoad();
262
  }
263
 
264
  // This is triggered AFTER "saveSettings" from 'Settings' class
@@ -315,6 +315,10 @@ class Main
315
  );
316
  }
317
 
 
 
 
 
318
  // Alter for debugging purposes; triggers before anything else
319
  // e.g. you're working on a website and there is no Dashboard access and you want to determine the handle name
320
  // if the handle name is not showing up, then the LINK stylesheet has been hardcoded (not enqueued the WordPress way)
@@ -322,25 +326,15 @@ class Main
322
  $styleTag = str_replace('<link ', '<link data-wpacu-debug-style-handle=\'' . $tagHandle . '\' ', $styleTag);
323
  }
324
 
325
- if (strpos($styleTag, 'data-wpacu-style-handle') === false
326
- && Menu::userCanManageAssets()
327
- && self::instance()->isFrontendEditView) {
328
- $styleTag = str_replace('<script ', '<script data-wpacu-style-handle=\'' . $tagHandle . '\' ', $styleTag);
329
  }
330
 
331
- if ( Plugin::preventAnyChanges() || self::isTestModeActive() ) {
332
- return $styleTag;
333
- }
334
-
335
- if (strpos($styleTag, 'data-wpacu-style-handle') === false) {
336
- $styleTag = str_replace( '<link ', '<link data-wpacu-style-handle=\'' . $tagHandle . '\' ', $styleTag );
337
- }
338
-
339
- return $styleTag;
340
  }, 10, 2);
341
 
342
  add_filter('script_loader_tag', static function($scriptTag, $tagHandle) {
343
- // Alter for debugging purposes; triggers before anything else
344
  // e.g. you're working on a website and there is no Dashboard access and you want to determine the handle name
345
  // if the handle name is not showing up, then the SCRIPT has been hardcoded (not enqueued the WordPress way)
346
  if (array_key_exists('wpacu_show_handle_names', $_GET)) {
@@ -369,7 +363,7 @@ class Main
369
  $scriptTag = str_replace('<script ', '<script data-wpacu-jquery-migrate-handle=1 ', $scriptTag);
370
  }
371
 
372
- return $scriptTag;
373
  }, 10, 2);
374
 
375
  Preloads::instance()->init();
@@ -427,7 +421,7 @@ SQL;
427
  // Fetch the page in the background to see what scripts/styles are already loading
428
  if ($this->isGetAssetsCall || $this->frontendShow()) {
429
  if ($this->isGetAssetsCall) {
430
- Misc::noAdminBarLoad();
431
  }
432
 
433
  // Save CSS handles list that is printed in the <HEAD>
@@ -577,21 +571,21 @@ SQL;
577
  global $wp_styles;
578
 
579
  if (current_action() === 'wp_print_styles') {
580
- wp_cache_set('wpacu_styles_object_after_wp_print_styles', $wp_styles);
581
  }
582
 
583
  $list = array();
584
 
585
  if (current_action() === 'wp_print_footer_scripts') {
586
- $cachedWpStyles = wp_cache_get('wpacu_styles_object_after_wp_print_styles');
587
  if (isset($cachedWpStyles->registered) && count($cachedWpStyles->registered) === count($wp_styles->registered)) {
588
  // The list was already generated in "wp_print_styles" and the number of registered assets are the same
589
  // Save resources and do not re-generate it
590
- $list = wp_cache_get('wpacu_styles_handles_marked_for_unload');
591
  }
592
  }
593
 
594
- if ( empty($list) ) {
595
  // [wpacu_lite]
596
  $nonAssetConfigPage = ( ! $this->isUpdateable && ! Misc::getShowOnFront() );
597
  // [/wpacu_lite]
@@ -616,6 +610,10 @@ SQL;
616
  $list = (array) $jsonList->styles;
617
  }
618
 
 
 
 
 
619
  // Any global unloaded styles? Append them
620
  if ( ! empty( $globalUnload['styles'] ) ) {
621
  foreach ( $globalUnload['styles'] as $handleStyle ) {
@@ -672,7 +670,7 @@ SQL;
672
  }
673
 
674
  if ( isset( $this->wpAllStyles['registered'] ) && ! empty( $this->wpAllStyles['registered'] ) ) {
675
- wp_cache_set( 'wpacu_all_styles_handles', array_keys( $this->wpAllStyles['registered'] ) );
676
  }
677
 
678
  // e.g. for test/debug mode or AJAX calls (where all assets have to load)
@@ -728,7 +726,8 @@ SQL;
728
  $handle = trim($handle);
729
 
730
  // Ignore auto generated handles for the hardcoded CSS as they were added for reference purposes
731
- if (strpos($handle, 'wpacu_hardcoded_link_') === 0) {
 
732
  continue;
733
  }
734
 
@@ -746,7 +745,7 @@ SQL;
746
  }
747
 
748
  if (current_action() === 'wp_print_styles') {
749
- wp_cache_set( 'wpacu_styles_handles_marked_for_unload', $list );
750
  }
751
 
752
  /* [wpacu_timing] */ Misc::scriptExecTimer( 'filter_dequeue_styles', 'end' ); /* [/wpacu_timing] */
@@ -862,17 +861,17 @@ SQL;
862
  global $wp_scripts;
863
 
864
  if (current_action() === 'wp_print_scripts') {
865
- wp_cache_set('wpacu_scripts_object_after_wp_print_scripts', $wp_scripts);
866
  }
867
 
868
  $list = array();
869
 
870
  if (current_action() === 'wp_print_footer_scripts') {
871
- $cachedWpScripts = wp_cache_get('wpacu_scripts_object_after_wp_print_scripts');
872
  if (isset($cachedWpScripts->registered) && count($cachedWpScripts->registered) === count($wp_scripts->registered)) {
873
  // The list was already generated in "wp_print_scripts" and the number of registered assets are the same
874
  // Save resources and do not re-generate it
875
- $list = wp_cache_get('wpacu_scripts_handles_marked_for_unload');
876
  }
877
  }
878
 
@@ -983,7 +982,6 @@ SQL;
983
  if ( empty( $list ) ) {
984
  /* [wpacu_timing] */
985
  Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
986
-
987
  return;
988
  }
989
 
@@ -991,7 +989,6 @@ SQL;
991
  if ( array_key_exists( 'wpacu_no_js_unload', $_GET ) || $this->preventAssetsSettings() ) {
992
  /* [wpacu_timing] */
993
  Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
994
-
995
  return;
996
  }
997
  }
@@ -1001,6 +998,10 @@ SQL;
1001
  foreach ($list as $handle) {
1002
  $handle = trim($handle);
1003
 
 
 
 
 
1004
  // Special Action for 'jquery-migrate' handler as its tied to 'jquery'
1005
  if ($handle === 'jquery-migrate' && isset($this->wpAllScripts['registered']['jquery'])) {
1006
  $jQueryRegScript = $this->wpAllScripts['registered']['jquery'];
@@ -1016,10 +1017,6 @@ SQL;
1016
  continue;
1017
  }
1018
 
1019
- if (array_key_exists('wpacu_debug', $_GET)) {
1020
- $this->allUnloadedAssets['js'][] = $handle;
1021
- }
1022
-
1023
  if (isset($ignoreChildParentList['scripts'], $this->wpAllScripts['registered'][$handle]->src) && is_array($ignoreChildParentList['scripts']) && array_key_exists($handle, $ignoreChildParentList['scripts'])) {
1024
  // Do not dequeue it as it's "children" will also be dequeued (ignore rule is applied)
1025
  // It will be stripped by cleaning its SCRIPT tag from the HTML Source
@@ -1042,7 +1039,7 @@ SQL;
1042
  }
1043
 
1044
  if (current_action() === 'wp_print_scripts') {
1045
- wp_cache_set( 'wpacu_scripts_handles_marked_for_unload', $list );
1046
  }
1047
 
1048
  /* [wpacu_timing] */ Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
@@ -1555,6 +1552,8 @@ SQL;
1555
  return;
1556
  }
1557
 
 
 
1558
  // Prevent plugins from altering the DOM
1559
  add_filter('w3tc_minify_enable', '__return_false');
1560
 
@@ -1834,7 +1833,7 @@ SQL;
1834
 
1835
  $data['ignore_child'] = $this->getIgnoreChildren();
1836
 
1837
- wp_cache_set('wpacu_settings_frontend_data', $data);
1838
  $this->parseTemplate('settings-frontend', $data, true);
1839
  } elseif ($isDashboardEditView) {
1840
  // AJAX call (not the classic WP one) from the WP Dashboard
@@ -1863,6 +1862,8 @@ SQL;
1863
  exit();
1864
  });
1865
  }
 
 
1866
  }
1867
 
1868
  /**
@@ -2000,17 +2001,11 @@ SQL;
2000
  $data['all']['hardcoded'] = (array) json_decode( $jsonH, ARRAY_A );
2001
 
2002
  if (isset($data['all']['hardcoded']['within_conditional_comments']) && ! empty($data['all']['hardcoded']['within_conditional_comments'])) {
2003
- wp_cache_set( 'wpacu_hardcoded_content_within_conditional_comments', $data['all']['hardcoded']['within_conditional_comments'] );
2004
  }
2005
  }
2006
  // [END] Hardcoded (if any)
2007
 
2008
- // [wpacu_pro]
2009
- if (isset($data['all']['unloaded_plugins']) && ! empty($data['all']['unloaded_plugins'])) {
2010
- wp_cache_add('wpacu_filtered_plugins', $data['all']['unloaded_plugins']);
2011
- }
2012
- // [/wpacu_pro]
2013
-
2014
  if ($data['plugin_settings']['assets_list_layout'] === 'by-location') {
2015
  $data['all'] = Sorting::appendLocation($data['all']);
2016
  } else {
@@ -2241,7 +2236,7 @@ SQL;
2241
  $data['all']['scripts'][$key]->wp = false;
2242
  }
2243
 
2244
- $initialScriptPos = wp_cache_get($obj->handle, 'wpacu_scripts_initial_positions');
2245
 
2246
  if ($initialScriptPos === 'body' || in_array($obj->handle, $this->assetsInFooter['scripts'])) {
2247
  $data['all']['scripts'][$key]->position = 'body';
@@ -2411,7 +2406,7 @@ SQL;
2411
  } else {
2412
  if ($wooCommerceShopPageId > 0 && Misc::isHomePage() && strpos(get_site_url(), '://') !== false) {
2413
  list($siteUrlAfterProtocol) = explode('://', get_site_url());
2414
- $currentPageUrlAfterProtocol = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
2415
 
2416
  if ($siteUrlAfterProtocol != $currentPageUrlAfterProtocol && (strpos($siteUrlAfterProtocol,
2417
  '/shop') !== false)
258
  // "Direct" AJAX call or "WP Remote Post" method used?
259
  // Do not trigger the admin bar as it's not relevant
260
  if ($this->isAjaxCall || $this->isGetAssetsCall) {
261
+ add_filter('show_admin_bar', '__return_false');
262
  }
263
 
264
  // This is triggered AFTER "saveSettings" from 'Settings' class
315
  );
316
  }
317
 
318
+ if ( Plugin::preventAnyChanges() || self::isTestModeActive() ) {
319
+ return $styleTag;
320
+ }
321
+
322
  // Alter for debugging purposes; triggers before anything else
323
  // e.g. you're working on a website and there is no Dashboard access and you want to determine the handle name
324
  // if the handle name is not showing up, then the LINK stylesheet has been hardcoded (not enqueued the WordPress way)
326
  $styleTag = str_replace('<link ', '<link data-wpacu-debug-style-handle=\'' . $tagHandle . '\' ', $styleTag);
327
  }
328
 
329
+ if (strpos($styleTag, 'data-wpacu-style-handle') === false) {
330
+ $styleTag = str_replace('<link ', '<link data-wpacu-style-handle=\'' . $tagHandle . '\' ', $styleTag);
 
 
331
  }
332
 
333
+ return $styleTag;
 
 
 
 
 
 
 
 
334
  }, 10, 2);
335
 
336
  add_filter('script_loader_tag', static function($scriptTag, $tagHandle) {
337
+ // Alter for debugging purposes; triggers before anything else
338
  // e.g. you're working on a website and there is no Dashboard access and you want to determine the handle name
339
  // if the handle name is not showing up, then the SCRIPT has been hardcoded (not enqueued the WordPress way)
340
  if (array_key_exists('wpacu_show_handle_names', $_GET)) {
363
  $scriptTag = str_replace('<script ', '<script data-wpacu-jquery-migrate-handle=1 ', $scriptTag);
364
  }
365
 
366
+ return $scriptTag;
367
  }, 10, 2);
368
 
369
  Preloads::instance()->init();
421
  // Fetch the page in the background to see what scripts/styles are already loading
422
  if ($this->isGetAssetsCall || $this->frontendShow()) {
423
  if ($this->isGetAssetsCall) {
424
+ add_filter('show_admin_bar', '__return_false');
425
  }
426
 
427
  // Save CSS handles list that is printed in the <HEAD>
571
  global $wp_styles;
572
 
573
  if (current_action() === 'wp_print_styles') {
574
+ ObjectCache::wpacu_cache_set('wpacu_styles_object_after_wp_print_styles', $wp_styles);
575
  }
576
 
577
  $list = array();
578
 
579
  if (current_action() === 'wp_print_footer_scripts') {
580
+ $cachedWpStyles = ObjectCache::wpacu_cache_get('wpacu_styles_object_after_wp_print_styles');
581
  if (isset($cachedWpStyles->registered) && count($cachedWpStyles->registered) === count($wp_styles->registered)) {
582
  // The list was already generated in "wp_print_styles" and the number of registered assets are the same
583
  // Save resources and do not re-generate it
584
+ $list = ObjectCache::wpacu_cache_get('wpacu_styles_handles_marked_for_unload');
585
  }
586
  }
587
 
588
+ if ( empty($list) || ! is_array($list) ) {
589
  // [wpacu_lite]
590
  $nonAssetConfigPage = ( ! $this->isUpdateable && ! Misc::getShowOnFront() );
591
  // [/wpacu_lite]
610
  $list = (array) $jsonList->styles;
611
  }
612
 
613
+ if (! is_array($list)) {
614
+ $list = array();
615
+ }
616
+
617
  // Any global unloaded styles? Append them
618
  if ( ! empty( $globalUnload['styles'] ) ) {
619
  foreach ( $globalUnload['styles'] as $handleStyle ) {
670
  }
671
 
672
  if ( isset( $this->wpAllStyles['registered'] ) && ! empty( $this->wpAllStyles['registered'] ) ) {
673
+ ObjectCache::wpacu_cache_set( 'wpacu_all_styles_handles', array_keys( $this->wpAllStyles['registered'] ) );
674
  }
675
 
676
  // e.g. for test/debug mode or AJAX calls (where all assets have to load)
726
  $handle = trim($handle);
727
 
728
  // Ignore auto generated handles for the hardcoded CSS as they were added for reference purposes
729
+ // They will get stripped later on via OptimizeCommon.php
730
+ if (strpos($handle, 'wpacu_hardcoded_link_') === 0) {
731
  continue;
732
  }
733
 
745
  }
746
 
747
  if (current_action() === 'wp_print_styles') {
748
+ ObjectCache::wpacu_cache_set( 'wpacu_styles_handles_marked_for_unload', $list );
749
  }
750
 
751
  /* [wpacu_timing] */ Misc::scriptExecTimer( 'filter_dequeue_styles', 'end' ); /* [/wpacu_timing] */
861
  global $wp_scripts;
862
 
863
  if (current_action() === 'wp_print_scripts') {
864
+ ObjectCache::wpacu_cache_set('wpacu_scripts_object_after_wp_print_scripts', $wp_scripts);
865
  }
866
 
867
  $list = array();
868
 
869
  if (current_action() === 'wp_print_footer_scripts') {
870
+ $cachedWpScripts = ObjectCache::wpacu_cache_get('wpacu_scripts_object_after_wp_print_scripts');
871
  if (isset($cachedWpScripts->registered) && count($cachedWpScripts->registered) === count($wp_scripts->registered)) {
872
  // The list was already generated in "wp_print_scripts" and the number of registered assets are the same
873
  // Save resources and do not re-generate it
874
+ $list = ObjectCache::wpacu_cache_get('wpacu_scripts_handles_marked_for_unload');
875
  }
876
  }
877
 
982
  if ( empty( $list ) ) {
983
  /* [wpacu_timing] */
984
  Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
 
985
  return;
986
  }
987
 
989
  if ( array_key_exists( 'wpacu_no_js_unload', $_GET ) || $this->preventAssetsSettings() ) {
990
  /* [wpacu_timing] */
991
  Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
 
992
  return;
993
  }
994
  }
998
  foreach ($list as $handle) {
999
  $handle = trim($handle);
1000
 
1001
+ if (array_key_exists('wpacu_debug', $_GET)) {
1002
+ $this->allUnloadedAssets['js'][] = $handle;
1003
+ }
1004
+
1005
  // Special Action for 'jquery-migrate' handler as its tied to 'jquery'
1006
  if ($handle === 'jquery-migrate' && isset($this->wpAllScripts['registered']['jquery'])) {
1007
  $jQueryRegScript = $this->wpAllScripts['registered']['jquery'];
1017
  continue;
1018
  }
1019
 
 
 
 
 
1020
  if (isset($ignoreChildParentList['scripts'], $this->wpAllScripts['registered'][$handle]->src) && is_array($ignoreChildParentList['scripts']) && array_key_exists($handle, $ignoreChildParentList['scripts'])) {
1021
  // Do not dequeue it as it's "children" will also be dequeued (ignore rule is applied)
1022
  // It will be stripped by cleaning its SCRIPT tag from the HTML Source
1039
  }
1040
 
1041
  if (current_action() === 'wp_print_scripts') {
1042
+ ObjectCache::wpacu_cache_set( 'wpacu_scripts_handles_marked_for_unload', $list );
1043
  }
1044
 
1045
  /* [wpacu_timing] */ Misc::scriptExecTimer( 'filter_dequeue_scripts', 'end' ); /* [/wpacu_timing] */
1552
  return;
1553
  }
1554
 
1555
+ /* [wpacu_timing] */ $wpacuTimingName = 'output_css_js_manager'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
1556
+
1557
  // Prevent plugins from altering the DOM
1558
  add_filter('w3tc_minify_enable', '__return_false');
1559
 
1833
 
1834
  $data['ignore_child'] = $this->getIgnoreChildren();
1835
 
1836
+ ObjectCache::wpacu_cache_set('wpacu_settings_frontend_data', $data);
1837
  $this->parseTemplate('settings-frontend', $data, true);
1838
  } elseif ($isDashboardEditView) {
1839
  // AJAX call (not the classic WP one) from the WP Dashboard
1862
  exit();
1863
  });
1864
  }
1865
+
1866
+ /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
1867
  }
1868
 
1869
  /**
2001
  $data['all']['hardcoded'] = (array) json_decode( $jsonH, ARRAY_A );
2002
 
2003
  if (isset($data['all']['hardcoded']['within_conditional_comments']) && ! empty($data['all']['hardcoded']['within_conditional_comments'])) {
2004
+ ObjectCache::wpacu_cache_set( 'wpacu_hardcoded_content_within_conditional_comments', $data['all']['hardcoded']['within_conditional_comments'] );
2005
  }
2006
  }
2007
  // [END] Hardcoded (if any)
2008
 
 
 
 
 
 
 
2009
  if ($data['plugin_settings']['assets_list_layout'] === 'by-location') {
2010
  $data['all'] = Sorting::appendLocation($data['all']);
2011
  } else {
2236
  $data['all']['scripts'][$key]->wp = false;
2237
  }
2238
 
2239
+ $initialScriptPos = ObjectCache::wpacu_cache_get($obj->handle, 'wpacu_scripts_initial_positions');
2240
 
2241
  if ($initialScriptPos === 'body' || in_array($obj->handle, $this->assetsInFooter['scripts'])) {
2242
  $data['all']['scripts'][$key]->position = 'body';
2406
  } else {
2407
  if ($wooCommerceShopPageId > 0 && Misc::isHomePage() && strpos(get_site_url(), '://') !== false) {
2408
  list($siteUrlAfterProtocol) = explode('://', get_site_url());
2409
+ $currentPageUrlAfterProtocol = parse_url(site_url(), PHP_URL_HOST) . $_SERVER['REQUEST_URI'];
2410
 
2411
  if ($siteUrlAfterProtocol != $currentPageUrlAfterProtocol && (strpos($siteUrlAfterProtocol,
2412
  '/shop') !== false)
classes/Misc.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
 
 
4
  /**
5
  * Class Misc
6
  * contains various common functions that are used by the plugin
@@ -31,16 +33,6 @@ class Misc
31
  */
32
  public $activeCachePlugins = array();
33
 
34
- /**
35
- * Misc constructor.
36
- */
37
- public function __construct()
38
- {
39
- if (isset($_REQUEST['wpacuNoAdminBar'])) {
40
- self::noAdminBarLoad();
41
- }
42
- }
43
-
44
  /**
45
  * @var
46
  */
@@ -336,6 +328,50 @@ class Misc
336
  return array();
337
  }
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  /**
340
  * @return bool
341
  */
@@ -356,14 +392,6 @@ class Misc
356
  return self::$showOnFront;
357
  }
358
 
359
- /**
360
- *
361
- */
362
- public static function noAdminBarLoad()
363
- {
364
- add_filter('show_admin_bar', '__return_false');
365
- }
366
-
367
  /**
368
  * @param $plugin
369
  *
@@ -418,12 +446,12 @@ class Misc
418
  */
419
  public static function getW3tcMasterConfig()
420
  {
421
- if (! wp_cache_get('wpacu_w3tc_master_config')) {
422
  $w3tcConfigMasterFile = WP_CONTENT_DIR . '/w3tc-config/master.php';
423
  $w3tcMasterConfig = FileSystem::file_get_contents($w3tcConfigMasterFile);
424
- wp_cache_set('wpacu_w3tc_master_config', trim($w3tcMasterConfig));
425
  } else {
426
- $w3tcMasterConfig = wp_cache_get('wpacu_w3tc_master_config');
427
  }
428
 
429
  return $w3tcMasterConfig;
@@ -721,8 +749,8 @@ SQL;
721
 
722
  $relSrc = str_replace( site_url(), '', $srcAlt );
723
 
724
- if (strpos($relSrc, '/wp-content/plugins') !== 0) {
725
- list (,$relSrc) = '/wp-content/plugins' . explode('/wp-content/plugins', $relSrc);
726
  }
727
 
728
  if (strpos($relSrc, $relPluginsUrl) !== false) {
@@ -1071,16 +1099,10 @@ SQL;
1071
 
1072
  if ($action === 'start') {
1073
  $startTime = (microtime(true) * 1000);
1074
-
1075
- // Do not overwrite it if it's already there (e.g. in a function called several times)
1076
- if (wp_cache_get($wpacuStartTimeName, 'wpacu_exec_time')) {
1077
- return '';
1078
- }
1079
-
1080
- wp_cache_set($wpacuStartTimeName, $startTime, 'wpacu_exec_time');
1081
  }
1082
 
1083
- if ($action === 'end' && ($startTime = wp_cache_get($wpacuStartTimeName, 'wpacu_exec_time'))) {
1084
  // End clock time in seconds
1085
  $endTime = (microtime(true) * 1000);
1086
  $scriptExecTime = ($endTime !== $startTime && $endTime > $startTime) ? ($endTime - $startTime) : 0;
@@ -1088,11 +1110,11 @@ SQL;
1088
  // Calculate script execution time
1089
  // Is there an existing exec time (e.g. from a function called several times)?
1090
  // Append it to the total execution time
1091
- if ($scriptExecTimeExisting = wp_cache_get($wpacuExecTimeName, 'wpacu_exec_time')) {
1092
  $scriptExecTime += $scriptExecTimeExisting;
1093
  }
1094
 
1095
- wp_cache_set($wpacuExecTimeName, $scriptExecTime, 'wpacu_exec_time');
1096
  return $scriptExecTime;
1097
  }
1098
 
@@ -1106,10 +1128,10 @@ SQL;
1106
  */
1107
  public static function getTimingValues($wpacuCacheKey)
1108
  {
1109
- $wpacuExecTiming = wp_cache_get( $wpacuCacheKey, 'wpacu_exec_time' ) ?: 0;
1110
 
1111
  $wpacuTimingFormatMs = str_replace('.00', '', number_format($wpacuExecTiming, 2));
1112
- $wpacuTimingFormatS = str_replace('.00', '', number_format(($wpacuExecTiming / 1000), 3));
1113
 
1114
  return array('ms' => $wpacuTimingFormatMs, 's' => $wpacuTimingFormatS);
1115
  }
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
4
+ use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
5
+
6
  /**
7
  * Class Misc
8
  * contains various common functions that are used by the plugin
33
  */
34
  public $activeCachePlugins = array();
35
 
 
 
 
 
 
 
 
 
 
 
36
  /**
37
  * @var
38
  */
328
  return array();
329
  }
330
 
331
+ /**
332
+ * @param bool $clean
333
+ *
334
+ * @return mixed|string
335
+ */
336
+ public static function getCurrentPageUrl($clean = true)
337
+ {
338
+ $currentPageUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . parse_url(site_url(), PHP_URL_HOST) . $_SERVER['REQUEST_URI'];
339
+
340
+ if ($clean && strpos($currentPageUrl, '?') !== false) {
341
+ list($currentPageUrl) = explode('?', $currentPageUrl);
342
+ }
343
+
344
+ return $currentPageUrl;
345
+ }
346
+
347
+ /**
348
+ * @param $src
349
+ * @param $assetKey
350
+ *
351
+ * @return string|string[]
352
+ */
353
+ public static function assetFromHrefToRelativeUri($src, $assetKey)
354
+ {
355
+ // Make the "src" relative in case the information will be imported from Staging to Live, it won't show the handle's link referencing to the staging URL in the "Overview" page and other similar pages as it's confusing
356
+ $localAssetPath = OptimizeCommon::getLocalAssetPath($src, (($assetKey === 'styles') ? 'css' : 'js'));
357
+
358
+ $relSrc = $src;
359
+
360
+ if ($localAssetPath) {
361
+ $relSrc = str_replace(ABSPATH, '', $relSrc);
362
+ }
363
+
364
+ $relSrc = str_replace(site_url(), '', $relSrc);
365
+
366
+ // Does it start with '//'? (protocol is missing) - the replacement above wasn't made
367
+ if (strpos($relSrc, '//') === 0) {
368
+ $siteUrlNoProtocol = str_replace(array('http:', 'https:'), '', site_url());
369
+ $relSrc = str_replace($siteUrlNoProtocol, '', $relSrc);
370
+ }
371
+
372
+ return $relSrc;
373
+ }
374
+
375
  /**
376
  * @return bool
377
  */
392
  return self::$showOnFront;
393
  }
394
 
 
 
 
 
 
 
 
 
395
  /**
396
  * @param $plugin
397
  *
446
  */
447
  public static function getW3tcMasterConfig()
448
  {
449
+ if (! ObjectCache::wpacu_cache_get('wpacu_w3tc_master_config')) {
450
  $w3tcConfigMasterFile = WP_CONTENT_DIR . '/w3tc-config/master.php';
451
  $w3tcMasterConfig = FileSystem::file_get_contents($w3tcConfigMasterFile);
452
+ ObjectCache::wpacu_cache_set('wpacu_w3tc_master_config', trim($w3tcMasterConfig));
453
  } else {
454
+ $w3tcMasterConfig = ObjectCache::wpacu_cache_get('wpacu_w3tc_master_config');
455
  }
456
 
457
  return $w3tcMasterConfig;
749
 
750
  $relSrc = str_replace( site_url(), '', $srcAlt );
751
 
752
+ if (strpos($relSrc, '/wp-content/plugins') !== false) {
753
+ list (,$relSrc) = explode('/wp-content/plugins', $relSrc);
754
  }
755
 
756
  if (strpos($relSrc, $relPluginsUrl) !== false) {
1099
 
1100
  if ($action === 'start') {
1101
  $startTime = (microtime(true) * 1000);
1102
+ ObjectCache::wpacu_cache_set($wpacuStartTimeName, $startTime, 'wpacu_exec_time');
 
 
 
 
 
 
1103
  }
1104
 
1105
+ if ($action === 'end' && ($startTime = ObjectCache::wpacu_cache_get($wpacuStartTimeName, 'wpacu_exec_time'))) {
1106
  // End clock time in seconds
1107
  $endTime = (microtime(true) * 1000);
1108
  $scriptExecTime = ($endTime !== $startTime && $endTime > $startTime) ? ($endTime - $startTime) : 0;
1110
  // Calculate script execution time
1111
  // Is there an existing exec time (e.g. from a function called several times)?
1112
  // Append it to the total execution time
1113
+ if ($scriptExecTimeExisting = ObjectCache::wpacu_cache_get($wpacuExecTimeName, 'wpacu_exec_time')) {
1114
  $scriptExecTime += $scriptExecTimeExisting;
1115
  }
1116
 
1117
+ ObjectCache::wpacu_cache_set($wpacuExecTimeName, $scriptExecTime, 'wpacu_exec_time');
1118
  return $scriptExecTime;
1119
  }
1120
 
1128
  */
1129
  public static function getTimingValues($wpacuCacheKey)
1130
  {
1131
+ $wpacuExecTiming = ObjectCache::wpacu_cache_get( $wpacuCacheKey, 'wpacu_exec_time' ) ?: 0;
1132
 
1133
  $wpacuTimingFormatMs = str_replace('.00', '', number_format($wpacuExecTiming, 2));
1134
+ $wpacuTimingFormatS = str_replace(array('.00', ','), '', number_format(($wpacuExecTiming / 1000), 3));
1135
 
1136
  return array('ms' => $wpacuTimingFormatMs, 's' => $wpacuTimingFormatS);
1137
  }
classes/ObjectCache.php ADDED
@@ -0,0 +1,750 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WpAssetCleanUp;
3
+
4
+ /**
5
+ * NOTE: This is from the original core file located /wp-includes/class-wp-object-cache.php
6
+ * Avoid the WordPress core $wp_object_cache global variable which is sometimes altered by 3rd party plugins
7
+ * This would make this plugin compatible with plugins such as "Redis Object Cache"
8
+ *
9
+ * Object Cache API: ObjectCache class
10
+ *
11
+ * @package WordPress
12
+ * @subpackage Cache
13
+ * @since 5.4.0
14
+ */
15
+
16
+ /**
17
+ * Core class that implements an object cache.
18
+ *
19
+ * The WordPress Object Cache is used to save on trips to the database. The
20
+ * Object Cache stores all of the cache data to memory and makes the cache
21
+ * contents available by using a key, which is used to name and later retrieve
22
+ * the cache contents.
23
+ *
24
+ * The Object Cache can be replaced by other caching mechanisms by placing files
25
+ * in the wp-content folder which is looked at in wp-settings. If that file
26
+ * exists, then this file will not be included.
27
+ *
28
+ * @since 2.0.0
29
+ */
30
+ class ObjectCache {
31
+
32
+ /**
33
+ * Holds the cached objects.
34
+ *
35
+ * @since 2.0.0
36
+ * @var array
37
+ */
38
+ private $cache = array();
39
+
40
+ /**
41
+ * The amount of times the cache data was already stored in the cache.
42
+ *
43
+ * @since 2.5.0
44
+ * @var int
45
+ */
46
+ public $cache_hits = 0;
47
+
48
+ /**
49
+ * Amount of times the cache did not have the request in cache.
50
+ *
51
+ * @since 2.0.0
52
+ * @var int
53
+ */
54
+ public $cache_misses = 0;
55
+
56
+ /**
57
+ * List of global cache groups.
58
+ *
59
+ * @since 3.0.0
60
+ * @var array
61
+ */
62
+ protected $global_groups = array();
63
+
64
+ /**
65
+ * The blog prefix to prepend to keys in non-global groups.
66
+ *
67
+ * @since 3.5.0
68
+ * @var string
69
+ */
70
+ private $blog_prefix;
71
+
72
+ /**
73
+ * Holds the value of is_multisite().
74
+ *
75
+ * @since 3.5.0
76
+ * @var bool
77
+ */
78
+ private $multisite;
79
+
80
+ /**
81
+ * Sets up object properties; PHP 5 style constructor.
82
+ *
83
+ * @since 2.0.8
84
+ */
85
+ public function __construct() {
86
+ $this->multisite = is_multisite();
87
+ $this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
88
+ }
89
+
90
+ /**
91
+ * Makes private properties readable for backward compatibility.
92
+ *
93
+ * @since 4.0.0
94
+ *
95
+ * @param string $name Property to get.
96
+ * @return mixed Property.
97
+ */
98
+ public function __get( $name ) {
99
+ return $this->$name;
100
+ }
101
+
102
+ /**
103
+ * Makes private properties settable for backward compatibility.
104
+ *
105
+ * @since 4.0.0
106
+ *
107
+ * @param string $name Property to set.
108
+ * @param mixed $value Property value.
109
+ * @return mixed Newly-set property.
110
+ */
111
+ public function __set( $name, $value ) {
112
+ return $this->$name = $value;
113
+ }
114
+
115
+ /**
116
+ * Makes private properties checkable for backward compatibility.
117
+ *
118
+ * @since 4.0.0
119
+ *
120
+ * @param string $name Property to check if set.
121
+ * @return bool Whether the property is set.
122
+ */
123
+ public function __isset( $name ) {
124
+ return isset( $this->$name );
125
+ }
126
+
127
+ /**
128
+ * Makes private properties un-settable for backward compatibility.
129
+ *
130
+ * @since 4.0.0
131
+ *
132
+ * @param string $name Property to unset.
133
+ */
134
+ public function __unset( $name ) {
135
+ unset( $this->$name );
136
+ }
137
+
138
+ /**
139
+ * Adds data to the cache if it doesn't already exist.
140
+ *
141
+ * @since 2.0.0
142
+ *
143
+ * @uses ObjectCache::_exists() Checks to see if the cache already has data.
144
+ * @uses ObjectCache::set() Sets the data after the checking the cache
145
+ * contents existence.
146
+ *
147
+ * @param int|string $key What to call the contents in the cache.
148
+ * @param mixed $data The contents to store in the cache.
149
+ * @param string $group Optional. Where to group the cache contents. Default 'default'.
150
+ * @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
151
+ * @return bool True on success, false if cache key and group already exist.
152
+ */
153
+ public function add( $key, $data, $group = 'default', $expire = 0 ) {
154
+ if ( wp_suspend_cache_addition() ) {
155
+ return false;
156
+ }
157
+
158
+ if ( empty( $group ) ) {
159
+ $group = 'default';
160
+ }
161
+
162
+ $id = $key;
163
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
164
+ $id = $this->blog_prefix . $key;
165
+ }
166
+
167
+ if ( $this->_exists( $id, $group ) ) {
168
+ return false;
169
+ }
170
+
171
+ return $this->set( $key, $data, $group, (int) $expire );
172
+ }
173
+
174
+ /**
175
+ * Sets the list of global cache groups.
176
+ *
177
+ * @since 3.0.0
178
+ *
179
+ * @param array $groups List of groups that are global.
180
+ */
181
+ public function add_global_groups( $groups ) {
182
+ $groups = (array) $groups;
183
+
184
+ $groups = array_fill_keys( $groups, true );
185
+ $this->global_groups = array_merge( $this->global_groups, $groups );
186
+ }
187
+
188
+ /**
189
+ * Decrements numeric cache item's value.
190
+ *
191
+ * @since 3.3.0
192
+ *
193
+ * @param int|string $key The cache key to decrement.
194
+ * @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
195
+ * @param string $group Optional. The group the key is in. Default 'default'.
196
+ * @return int|false The item's new value on success, false on failure.
197
+ */
198
+ public function decr( $key, $offset = 1, $group = 'default' ) {
199
+ if ( empty( $group ) ) {
200
+ $group = 'default';
201
+ }
202
+
203
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
204
+ $key = $this->blog_prefix . $key;
205
+ }
206
+
207
+ if ( ! $this->_exists( $key, $group ) ) {
208
+ return false;
209
+ }
210
+
211
+ if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
212
+ $this->cache[ $group ][ $key ] = 0;
213
+ }
214
+
215
+ $offset = (int) $offset;
216
+
217
+ $this->cache[ $group ][ $key ] -= $offset;
218
+
219
+ if ( $this->cache[ $group ][ $key ] < 0 ) {
220
+ $this->cache[ $group ][ $key ] = 0;
221
+ }
222
+
223
+ return $this->cache[ $group ][ $key ];
224
+ }
225
+
226
+ /**
227
+ * Removes the contents of the cache key in the group.
228
+ *
229
+ * If the cache key does not exist in the group, then nothing will happen.
230
+ *
231
+ * @since 2.0.0
232
+ *
233
+ * @param int|string $key What the contents in the cache are called.
234
+ * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
235
+ * @param bool $deprecated Optional. Unused. Default false.
236
+ * @return bool False if the contents weren't deleted and true on success.
237
+ */
238
+ public function delete( $key, $group = 'default', $deprecated = false ) {
239
+ if ( empty( $group ) ) {
240
+ $group = 'default';
241
+ }
242
+
243
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
244
+ $key = $this->blog_prefix . $key;
245
+ }
246
+
247
+ if ( ! $this->_exists( $key, $group ) ) {
248
+ return false;
249
+ }
250
+
251
+ unset( $this->cache[ $group ][ $key ] );
252
+ return true;
253
+ }
254
+
255
+ /**
256
+ * Clears the object cache of all data.
257
+ *
258
+ * @since 2.0.0
259
+ *
260
+ * @return true Always returns true.
261
+ */
262
+ public function flush() {
263
+ $this->cache = array();
264
+
265
+ return true;
266
+ }
267
+
268
+ /**
269
+ * Retrieves the cache contents, if it exists.
270
+ *
271
+ * The contents will be first attempted to be retrieved by searching by the
272
+ * key in the cache group. If the cache is hit (success) then the contents
273
+ * are returned.
274
+ *
275
+ * On failure, the number of cache misses will be incremented.
276
+ *
277
+ * @since 2.0.0
278
+ *
279
+ * @param int|string $key What the contents in the cache are called.
280
+ * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
281
+ * @param bool $force Optional. Unused. Whether to force a refetch rather than relying on the local
282
+ * cache. Default false.
283
+ * @param bool $found Optional. Whether the key was found in the cache (passed by reference).
284
+ * Disambiguates a return of false, a storable value. Default null.
285
+ * @return mixed|false The cache contents on success, false on failure to retrieve contents.
286
+ */
287
+ public function get( $key, $group = 'default', $force = false, &$found = null ) {
288
+ if ( empty( $group ) ) {
289
+ $group = 'default';
290
+ }
291
+
292
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
293
+ $key = $this->blog_prefix . $key;
294
+ }
295
+
296
+ if ( $this->_exists( $key, $group ) ) {
297
+ $found = true;
298
+ $this->cache_hits += 1;
299
+ if ( is_object( $this->cache[ $group ][ $key ] ) ) {
300
+ return clone $this->cache[ $group ][ $key ];
301
+ } else {
302
+ return $this->cache[ $group ][ $key ];
303
+ }
304
+ }
305
+
306
+ $found = false;
307
+ $this->cache_misses += 1;
308
+ return false;
309
+ }
310
+
311
+ /**
312
+ * Increments numeric cache item's value.
313
+ *
314
+ * @since 3.3.0
315
+ *
316
+ * @param int|string $key The cache key to increment
317
+ * @param int $offset Optional. The amount by which to increment the item's value. Default 1.
318
+ * @param string $group Optional. The group the key is in. Default 'default'.
319
+ * @return int|false The item's new value on success, false on failure.
320
+ */
321
+ public function incr( $key, $offset = 1, $group = 'default' ) {
322
+ if ( empty( $group ) ) {
323
+ $group = 'default';
324
+ }
325
+
326
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
327
+ $key = $this->blog_prefix . $key;
328
+ }
329
+
330
+ if ( ! $this->_exists( $key, $group ) ) {
331
+ return false;
332
+ }
333
+
334
+ if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
335
+ $this->cache[ $group ][ $key ] = 0;
336
+ }
337
+
338
+ $offset = (int) $offset;
339
+
340
+ $this->cache[ $group ][ $key ] += $offset;
341
+
342
+ if ( $this->cache[ $group ][ $key ] < 0 ) {
343
+ $this->cache[ $group ][ $key ] = 0;
344
+ }
345
+
346
+ return $this->cache[ $group ][ $key ];
347
+ }
348
+
349
+ /**
350
+ * Replaces the contents in the cache, if contents already exist.
351
+ *
352
+ * @since 2.0.0
353
+ *
354
+ * @see ObjectCache::set()
355
+ *
356
+ * @param int|string $key What to call the contents in the cache.
357
+ * @param mixed $data The contents to store in the cache.
358
+ * @param string $group Optional. Where to group the cache contents. Default 'default'.
359
+ * @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
360
+ * @return bool False if not exists, true if contents were replaced.
361
+ */
362
+ public function replace( $key, $data, $group = 'default', $expire = 0 ) {
363
+ if ( empty( $group ) ) {
364
+ $group = 'default';
365
+ }
366
+
367
+ $id = $key;
368
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
369
+ $id = $this->blog_prefix . $key;
370
+ }
371
+
372
+ if ( ! $this->_exists( $id, $group ) ) {
373
+ return false;
374
+ }
375
+
376
+ return $this->set( $key, $data, $group, (int) $expire );
377
+ }
378
+
379
+ /**
380
+ * Resets cache keys.
381
+ *
382
+ * @since 3.0.0
383
+ *
384
+ * @deprecated 3.5.0 Use switch_to_blog()
385
+ * @see switch_to_blog()
386
+ */
387
+ public function reset() {
388
+ _deprecated_function( __FUNCTION__, '3.5.0', 'switch_to_blog()' );
389
+
390
+ // Clear out non-global caches since the blog ID has changed.
391
+ foreach ( array_keys( $this->cache ) as $group ) {
392
+ if ( ! isset( $this->global_groups[ $group ] ) ) {
393
+ unset( $this->cache[ $group ] );
394
+ }
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Sets the data contents into the cache.
400
+ *
401
+ * The cache contents are grouped by the $group parameter followed by the
402
+ * $key. This allows for duplicate ids in unique groups. Therefore, naming of
403
+ * the group should be used with care and should follow normal function
404
+ * naming guidelines outside of core WordPress usage.
405
+ *
406
+ * The $expire parameter is not used, because the cache will automatically
407
+ * expire for each time a page is accessed and PHP finishes. The method is
408
+ * more for cache plugins which use files.
409
+ *
410
+ * @since 2.0.0
411
+ *
412
+ * @param int|string $key What to call the contents in the cache.
413
+ * @param mixed $data The contents to store in the cache.
414
+ * @param string $group Optional. Where to group the cache contents. Default 'default'.
415
+ * @param int $expire Not Used.
416
+ * @return true Always returns true.
417
+ */
418
+ public function set( $key, $data, $group = 'default', $expire = 0 ) {
419
+ if ( empty( $group ) ) {
420
+ $group = 'default';
421
+ }
422
+
423
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
424
+ $key = $this->blog_prefix . $key;
425
+ }
426
+
427
+ if ( is_object( $data ) ) {
428
+ $data = clone $data;
429
+ }
430
+
431
+ $this->cache[ $group ][ $key ] = $data;
432
+ return true;
433
+ }
434
+
435
+ /**
436
+ * Echoes the stats of the caching.
437
+ *
438
+ * Gives the cache hits, and cache misses. Also prints every cached group,
439
+ * key and the data.
440
+ *
441
+ * @since 2.0.0
442
+ */
443
+ public function stats() {
444
+ echo '<p>';
445
+ echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
446
+ echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
447
+ echo '</p>';
448
+ echo '<ul>';
449
+ foreach ( $this->cache as $group => $cache ) {
450
+ echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
451
+ }
452
+ echo '</ul>';
453
+ }
454
+
455
+ /**
456
+ * Switches the internal blog ID.
457
+ *
458
+ * This changes the blog ID used to create keys in blog specific groups.
459
+ *
460
+ * @since 3.5.0
461
+ *
462
+ * @param int $blog_id Blog ID.
463
+ */
464
+ public function switch_to_blog( $blog_id ) {
465
+ $blog_id = (int) $blog_id;
466
+ $this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
467
+ }
468
+
469
+ /**
470
+ * Serves as a utility function to determine whether a key exists in the cache.
471
+ *
472
+ * @since 3.4.0
473
+ *
474
+ * @param int|string $key Cache key to check for existence.
475
+ * @param string $group Cache group for the key existence check.
476
+ * @return bool Whether the key exists in the cache for the given group.
477
+ */
478
+ protected function _exists( $key, $group ) {
479
+ return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
480
+ }
481
+
482
+ /**
483
+ * [START] Functions to call (reference: /wp-includes/cache.php)
484
+ */
485
+ /**
486
+ * Adds data to the cache, if the cache key doesn't already exist.
487
+ *
488
+ * @since 2.0.0
489
+ *
490
+ * @see ObjectCache::add()
491
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
492
+ *
493
+ * @param int|string $key The cache key to use for retrieval later.
494
+ * @param mixed $data The data to add to the cache.
495
+ * @param string $group Optional. The group to add the cache to. Enables the same key
496
+ * to be used across groups. Default empty.
497
+ * @param int $expire Optional. When the cache data should expire, in seconds.
498
+ * Default 0 (no expiration).
499
+ * @return bool True on success, false if cache key and group already exist.
500
+ */
501
+ public static function wpacu_cache_add( $key, $data, $group = '', $expire = 0 ) {
502
+ global $wpacu_object_cache;
503
+
504
+ return $wpacu_object_cache->add( $key, $data, $group, (int) $expire );
505
+ }
506
+
507
+ /**
508
+ * Closes the cache.
509
+ *
510
+ * This function has ceased to do anything since WordPress 2.5. The
511
+ * functionality was removed along with the rest of the persistent cache.
512
+ *
513
+ * This does not mean that plugins can't implement this function when they need
514
+ * to make sure that the cache is cleaned up after WordPress no longer needs it.
515
+ *
516
+ * @since 2.0.0
517
+ *
518
+ * @return true Always returns true.
519
+ */
520
+ public static function wpacu_cache_close() {
521
+ return true;
522
+ }
523
+
524
+ /**
525
+ * Decrements numeric cache item's value.
526
+ *
527
+ * @since 3.3.0
528
+ *
529
+ * @see ObjectCache::decr()
530
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
531
+ *
532
+ * @param int|string $key The cache key to decrement.
533
+ * @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
534
+ * @param string $group Optional. The group the key is in. Default empty.
535
+ * @return int|false The item's new value on success, false on failure.
536
+ */
537
+ public static function wpacu_cache_decr( $key, $offset = 1, $group = '' ) {
538
+ global $wpacu_object_cache;
539
+
540
+ return $wpacu_object_cache->decr( $key, $offset, $group );
541
+ }
542
+
543
+ /**
544
+ * Removes the cache contents matching key and group.
545
+ *
546
+ * @since 2.0.0
547
+ *
548
+ * @see ObjectCache::delete()
549
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
550
+ *
551
+ * @param int|string $key What the contents in the cache are called.
552
+ * @param string $group Optional. Where the cache contents are grouped. Default empty.
553
+ * @return bool True on successful removal, false on failure.
554
+ */
555
+ public static function wpacu_cache_delete( $key, $group = '' ) {
556
+ global $wpacu_object_cache;
557
+
558
+ return $wpacu_object_cache->delete( $key, $group );
559
+ }
560
+
561
+ /**
562
+ * Removes all cache items.
563
+ *
564
+ * @since 2.0.0
565
+ *
566
+ * @see ObjectCache::flush()
567
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
568
+ *
569
+ * @return bool True on success, false on failure.
570
+ */
571
+ public static function wpacu_cache_flush() {
572
+ global $wpacu_object_cache;
573
+
574
+ return $wpacu_object_cache->flush();
575
+ }
576
+
577
+ /**
578
+ * Retrieves the cache contents from the cache by key and group.
579
+ *
580
+ * @since 2.0.0
581
+ *
582
+ * @see ObjectCache::get()
583
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
584
+ *
585
+ * @param int|string $key The key under which the cache contents are stored.
586
+ * @param string $group Optional. Where the cache contents are grouped. Default empty.
587
+ * @param bool $force Optional. Whether to force an update of the local cache from the persistent
588
+ * cache. Default false.
589
+ * @param bool $found Optional. Whether the key was found in the cache (passed by reference).
590
+ * Disambiguates a return of false, a storable value. Default null.
591
+ * @return bool|mixed False on failure to retrieve contents or the cache
592
+ * contents on success
593
+ */
594
+ public static function wpacu_cache_get( $key, $group = '', $force = false, &$found = null ) {
595
+ global $wpacu_object_cache;
596
+
597
+ return $wpacu_object_cache->get( $key, $group, $force, $found );
598
+ }
599
+
600
+ /**
601
+ * Increment numeric cache item's value
602
+ *
603
+ * @since 3.3.0
604
+ *
605
+ * @see ObjectCache::incr()
606
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
607
+ *
608
+ * @param int|string $key The key for the cache contents that should be incremented.
609
+ * @param int $offset Optional. The amount by which to increment the item's value. Default 1.
610
+ * @param string $group Optional. The group the key is in. Default empty.
611
+ * @return int|false The item's new value on success, false on failure.
612
+ */
613
+ public static function wpacu_cache_incr( $key, $offset = 1, $group = '' ) {
614
+ global $wpacu_object_cache;
615
+
616
+ return $wpacu_object_cache->incr( $key, $offset, $group );
617
+ }
618
+
619
+ /**
620
+ * Sets up Object Cache Global and assigns it.
621
+ *
622
+ * @since 2.0.0
623
+ *
624
+ * @global ObjectCache $wpacu_object_cache
625
+ */
626
+ public static function wpacu_cache_init() {
627
+ $GLOBALS['wpacu_object_cache'] = new ObjectCache();
628
+ }
629
+
630
+ /**
631
+ * Replaces the contents of the cache with new data.
632
+ *
633
+ * @since 2.0.0
634
+ *
635
+ * @see ObjectCache::replace()
636
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
637
+ *
638
+ * @param int|string $key The key for the cache data that should be replaced.
639
+ * @param mixed $data The new data to store in the cache.
640
+ * @param string $group Optional. The group for the cache data that should be replaced.
641
+ * Default empty.
642
+ * @param int $expire Optional. When to expire the cache contents, in seconds.
643
+ * Default 0 (no expiration).
644
+ * @return bool False if original value does not exist, true if contents were replaced
645
+ */
646
+ public static function wpacu_cache_replace( $key, $data, $group = '', $expire = 0 ) {
647
+ global $wpacu_object_cache;
648
+
649
+ return $wpacu_object_cache->replace( $key, $data, $group, (int) $expire );
650
+ }
651
+
652
+ /**
653
+ * Saves the data to the cache.
654
+ *
655
+ * Differs from ObjectCache::wpacu_cache_add) and wp_cache_replace() in that it will always write data.
656
+ *
657
+ * @since 2.0.0
658
+ *
659
+ * @see ObjectCache::set()
660
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
661
+ *
662
+ * @param int|string $key The cache key to use for retrieval later.
663
+ * @param mixed $data The contents to store in the cache.
664
+ * @param string $group Optional. Where to group the cache contents. Enables the same key
665
+ * to be used across groups. Default empty.
666
+ * @param int $expire Optional. When to expire the cache contents, in seconds.
667
+ * Default 0 (no expiration).
668
+ * @return bool True on success, false on failure.
669
+ */
670
+ public static function wpacu_cache_set( $key, $data, $group = '', $expire = 0 ) {
671
+ global $wpacu_object_cache;
672
+
673
+ return $wpacu_object_cache->set( $key, $data, $group, (int) $expire );
674
+ }
675
+
676
+ /**
677
+ * Switches the internal blog ID.
678
+ *
679
+ * This changes the blog id used to create keys in blog specific groups.
680
+ *
681
+ * @since 3.5.0
682
+ *
683
+ * @see ObjectCache::switch_to_blog()
684
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
685
+ *
686
+ * @param int $blog_id Site ID.
687
+ */
688
+ public static function wpacu_cache_switch_to_blog( $blog_id ) {
689
+ global $wpacu_object_cache;
690
+
691
+ $wpacu_object_cache->switch_to_blog( $blog_id );
692
+ }
693
+
694
+ /**
695
+ * Adds a group or set of groups to the list of global groups.
696
+ *
697
+ * @since 2.6.0
698
+ *
699
+ * @see ObjectCache::add_global_groups()
700
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
701
+ *
702
+ * @param string|array $groups A group or an array of groups to add.
703
+ */
704
+ public static function wpacu_cache_add_global_groups( $groups ) {
705
+ global $wpacu_object_cache;
706
+
707
+ $wpacu_object_cache->add_global_groups( $groups );
708
+ }
709
+
710
+ /**
711
+ * Adds a group or set of groups to the list of non-persistent groups.
712
+ *
713
+ * @since 2.6.0
714
+ *
715
+ * @param string|array $groups A group or an array of groups to add.
716
+ */
717
+ public static function wpacu_cache_add_non_persistent_groups( $groups ) {
718
+ // Default cache doesn't persist so nothing to do here.
719
+ }
720
+
721
+ /**
722
+ * Reset internal cache keys and structures.
723
+ *
724
+ * If the cache back end uses global blog or site IDs as part of its cache keys,
725
+ * this function instructs the back end to reset those keys and perform any cleanup
726
+ * since blog or site IDs have changed since cache init.
727
+ *
728
+ * This function is deprecated. Use wp_cache_switch_to_blog() instead of this
729
+ * function when preparing the cache for a blog switch. For clearing the cache
730
+ * during unit tests, consider using wp_cache_init(). wp_cache_init() is not
731
+ * recommended outside of unit tests as the performance penalty for using it is
732
+ * high.
733
+ *
734
+ * @since 2.6.0
735
+ * @deprecated 3.5.0 ObjectCache::reset()
736
+ * @see ObjectCache::reset()
737
+ *
738
+ * @global ObjectCache $wpacu_object_cache Object cache global instance.
739
+ */
740
+ public static function wpacu_cache_reset() {
741
+ _deprecated_function( __FUNCTION__, '3.5.0', 'ObjectCache::reset()' );
742
+
743
+ global $wpacu_object_cache;
744
+
745
+ $wpacu_object_cache->reset();
746
+ }
747
+ /**
748
+ * [END] Functions to call (reference: /wp-includes/cache.php)
749
+ */
750
+ }
classes/OptimiseAssets/CombineCss.php CHANGED
@@ -5,6 +5,8 @@ use WpAssetCleanUp\Main;
5
  use WpAssetCleanUp\Menu;
6
  use WpAssetCleanUp\FileSystem;
7
  use WpAssetCleanUp\Misc;
 
 
8
 
9
  /**
10
  * Class CombineCss
@@ -24,7 +26,7 @@ class CombineCss
24
  */
25
  public static function doCombine($htmlSource)
26
  {
27
- if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('DOMDocument')) && class_exists('DOMXpath')) {
28
  return $htmlSource;
29
  }
30
 
@@ -32,6 +34,9 @@ class CombineCss
32
  return $htmlSource;
33
  }
34
 
 
 
 
35
  // Speed up processing by getting the already existing final CSS file URI
36
  // This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
37
  $storageJsonContents = OptimizeCommon::getAssetCachedData(self::$jsonStorageFile, OptimizeCss::getRelPathCssCacheDir(), 'css');
@@ -39,7 +44,13 @@ class CombineCss
39
  // $uriToFinalCssFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathCssCacheDir()
40
  // which is usually "wp-content/cache/asset-cleanup/css/"
41
 
42
- if (empty($storageJsonContents)) {
 
 
 
 
 
 
43
  $storageJsonContentsToSave = array();
44
 
45
  /*
@@ -48,25 +59,20 @@ class CombineCss
48
  // Nothing in the database records or the retrieved cached file does not exist?
49
  OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
50
 
51
- // Fetch the DOM
52
- $documentForCSS = new \DOMDocument();
53
-
54
- libxml_use_internal_errors(true);
55
-
56
  $storageJsonContents = array();
57
 
58
- // Strip NOSCRIPT tags
59
- $htmlSourceAlt = preg_replace('@<(noscript)[^>]*?>.*?</\\1>@si', '', $htmlSource);
60
- $documentForCSS->loadHTML($htmlSourceAlt);
61
 
62
  foreach (array('head', 'body') as $docLocationTag) {
63
  $combinedUriPathsGroup = $localAssetsPathsGroup = $linkHrefsGroup = array();
 
 
 
64
 
65
- $docLocationElements = $documentForCSS->getElementsByTagName($docLocationTag)->item(0);
66
  if ($docLocationElements === null) { continue; }
67
 
68
- $xpath = new \DOMXpath($documentForCSS);
69
- $linkTags = $xpath->query('/html/'.$docLocationTag.'/link[@rel="stylesheet"]');
70
  if ($linkTags === null) { continue; }
71
 
72
  foreach ($linkTags as $tagObject) {
@@ -78,22 +84,35 @@ class CombineCss
78
  if (isset($linkAttributes['rel'], $linkAttributes['href']) && $linkAttributes['href']) {
79
  $href = (string) $linkAttributes['href'];
80
 
81
- // 1) Check if there is any rel="preload" (Basic) connected to the rel="stylesheet"
82
- // making sure the file is not added to the final CSS combined file
83
 
84
- // 2) Only combine media "all" and the ones with no media
85
- // Do not combine media='only screen and (max-width: 768px)', media='print' etc.
86
- if (isset($linkAttributes['data-wpacu-to-be-preloaded-basic']) && $linkAttributes['data-wpacu-to-be-preloaded-basic']) {
87
- continue;
 
 
88
  }
89
 
90
- // Separate each combined group by the "media" attribute; e.g. we don't want "all" and "print" mixed
91
- $mediaValue = (array_key_exists('media', $linkAttributes) && $linkAttributes['media']) ? $linkAttributes['media'] : 'all';
 
 
92
 
93
  if (self::skipCombine($linkAttributes['href'])) {
94
  continue;
95
  }
96
 
 
 
 
 
 
 
 
 
 
97
  // Was it optimized and has the URL updated? Check the Source URL to determine if it should be skipped from combining
98
  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'])) {
99
  continue;
@@ -108,9 +127,16 @@ class CombineCss
108
 
109
  // It will skip external stylesheets (from a different domain)
110
  if ( $localAssetPath ) {
 
 
 
 
 
 
111
  $combinedUriPathsGroup[$mediaValue][] = OptimizeCommon::getSourceRelPath($href);
112
  $localAssetsPathsGroup[$mediaValue][$href] = $localAssetPath;
113
  $linkHrefsGroup[$mediaValue][] = $href;
 
114
  }
115
  }
116
  }
@@ -128,12 +154,14 @@ class CombineCss
128
 
129
  $localAssetsPaths = $localAssetsPathsGroup[$mediaValue];
130
  $linkHrefs = $linkHrefsGroup[$mediaValue];
 
131
 
132
- $shaOneForCombinedCss = self::generateShaOneForCombinedCss($combinedUriPaths);
133
 
134
  $maybeDoCssCombine = self::maybeDoCssCombine(
135
  $shaOneForCombinedCss,
136
  $localAssetsPaths, $linkHrefs,
 
137
  $docLocationTag
138
  );
139
 
@@ -197,12 +225,32 @@ class CombineCss
197
  $finalTagUrl = OptimizeCommon::filterWpContentUrl($cdnUrlForCss) . OptimizeCss::getRelPathCssCacheDir() . $storageJsonContentLocation['uri_to_final_css_file'];
198
 
199
  $finalCssTagAttrs = array();
200
- $finalCssTagAttrs['rel'] = 'stylesheet';
201
- $finalCssTagAttrs['media'] = $mediaValue;
202
 
203
- $finalCssTag = <<<HTML
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  <link rel='stylesheet' id='wpacu-combined-css-{$docLocationTag}-{$groupLocation}' href='{$finalTagUrl}' type='text/css' media='{$mediaValue}' />
205
  HTML;
 
 
 
 
206
  // In case one (e.g. usually a developer) needs to alter it
207
  $finalCssTag = apply_filters(
208
  'wpacu_combined_css_tag',
@@ -215,18 +263,23 @@ HTML;
215
  )
216
  );
217
 
 
 
 
218
  $htmlSourceBeforeAnyLinkTagReplacement = $htmlSource;
219
 
220
  // Detect first LINK tag from the <$locationTag> and replace it with the final combined LINK tag
221
  $firstLinkTag = OptimizeCss::getFirstLinkTag($storageJsonContentLocation['link_hrefs'][0], $htmlSource);
222
 
223
  if ($firstLinkTag) {
224
- $htmlSource = str_replace($firstLinkTag, $finalCssTag, $htmlSource);
 
225
  }
226
 
227
  if ($htmlSource !== $htmlSourceBeforeAnyLinkTagReplacement) {
228
  $htmlSource = self::stripJustCombinedLinkTags(
229
  $storageJsonContentLocation['link_hrefs'],
 
230
  $htmlSource
231
  ); // Strip the combined files to avoid duplicate code
232
 
@@ -247,11 +300,12 @@ HTML;
247
 
248
  /**
249
  * @param $filesSources
 
250
  * @param $htmlSource
251
  *
252
  * @return mixed
253
  */
254
- public static function stripJustCombinedLinkTags($filesSources, $htmlSource)
255
  {
256
  preg_match_all('#<link[^>]*(stylesheet|preload)[^>]*(>)#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
257
 
@@ -271,7 +325,7 @@ HTML;
271
  $domTag->loadHTML($matchedSourceFromTag);
272
 
273
  foreach ($domTag->getElementsByTagName('link') as $tagObject) {
274
- if (! $tagObject->hasAttributes()) { continue; }
275
 
276
  foreach ($tagObject->attributes as $tagAttrs) {
277
  if ($tagAttrs->nodeName === 'href') {
@@ -280,7 +334,7 @@ HTML;
280
  if (in_array($relNodeValue, $filesSources)) {
281
  $htmlSourceBeforeLinkTagReplacement = $htmlSource;
282
 
283
- $htmlSource = str_replace(array($matchedSourceFromTag."\n", $matchedSourceFromTag), '', $htmlSource);
284
 
285
  if ($htmlSource !== $htmlSourceBeforeLinkTagReplacement) {
286
  $linkTagsStrippedNo++;
@@ -345,19 +399,15 @@ HTML;
345
  * @param $shaOneForCombinedCss
346
  * @param $localAssetsPaths
347
  * @param $linkHrefs
 
348
  * @param $docLocationTag
349
  *
350
  * @return array
351
  */
352
- public static function maybeDoCssCombine($shaOneForCombinedCss, $localAssetsPaths, $linkHrefs, $docLocationTag)
353
  {
354
- $current_user = wp_get_current_user();
355
- $dirToUserCachedFile = ((isset($current_user->ID) && $current_user->ID > 0) ? 'logged-in/' : '');
356
-
357
- $uriToFinalCssFile = $dirToUserCachedFile . $docLocationTag . '-' .$shaOneForCombinedCss . '.css';
358
-
359
- $localFinalCssFile = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir() . $uriToFinalCssFile;
360
- $localDirForCssFile = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir() . $dirToUserCachedFile;
361
 
362
  // Only combine if $shaOneCombinedUriPaths.css does not exist
363
  // If "?ver" value changes on any of the assets or the asset list changes in any way
@@ -379,6 +429,8 @@ HTML;
379
 
380
  $finalCombinedCssContent .= '/*! '.str_replace(ABSPATH, '/', $localAssetsPath)." */\n";
381
  $finalCombinedCssContent .= OptimizeCss::maybeFixCssContent($cssContent, $pathToAssetDir . '/') . "\n";
 
 
382
  }
383
  }
384
 
@@ -389,15 +441,9 @@ HTML;
389
  $finalCombinedCssContent = FontsGoogleRemove::cleanFontFaceReferences($finalCombinedCssContent);
390
  }
391
 
392
- if ($finalCombinedCssContent) {
393
- if ($dirToUserCachedFile !== '' && isset($current_user->ID) && $current_user->ID > 0 && ! is_dir($localDirForCssFile)) {
394
- $makeLocalDirForCss = @mkdir($localDirForCssFile);
395
-
396
- if (! $makeLocalDirForCss) {
397
- return array('uri_final_css_file' => '', 'local_final_css_file' => '');
398
- }
399
- }
400
 
 
401
  FileSystem::file_put_contents($localFinalCssFile, $finalCombinedCssContent);
402
  }
403
  }
@@ -411,12 +457,100 @@ HTML;
411
 
412
  /**
413
  * @param $combinedUriPaths
 
414
  *
415
  * @return string
416
  */
417
- public static function generateShaOneForCombinedCss($combinedUriPaths)
418
  {
419
- return sha1(implode('', $combinedUriPaths));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
421
 
422
  /**
5
  use WpAssetCleanUp\Menu;
6
  use WpAssetCleanUp\FileSystem;
7
  use WpAssetCleanUp\Misc;
8
+ use WpAssetCleanUp\ObjectCache;
9
+ use WpAssetCleanUp\Preloads;
10
 
11
  /**
12
  * Class CombineCss
26
  */
27
  public static function doCombine($htmlSource)
28
  {
29
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument')) && class_exists('\DOMXpath')) {
30
  return $htmlSource;
31
  }
32
 
34
  return $htmlSource;
35
  }
36
 
37
+ global $wp_styles;
38
+ $wpacuRegisteredStyles = $wp_styles->registered;
39
+
40
  // Speed up processing by getting the already existing final CSS file URI
41
  // This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
42
  $storageJsonContents = OptimizeCommon::getAssetCachedData(self::$jsonStorageFile, OptimizeCss::getRelPathCssCacheDir(), 'css');
44
  // $uriToFinalCssFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathCssCacheDir()
45
  // which is usually "wp-content/cache/asset-cleanup/css/"
46
 
47
+ $skipCache = false; // default
48
+
49
+ if (isset($_GET['wpacu_no_cache'])) {
50
+ $skipCache = true;
51
+ }
52
+
53
+ if ( $skipCache || empty($storageJsonContents) ) {
54
  $storageJsonContentsToSave = array();
55
 
56
  /*
59
  // Nothing in the database records or the retrieved cached file does not exist?
60
  OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
61
 
 
 
 
 
 
62
  $storageJsonContents = array();
63
 
64
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'combineCss');
 
 
65
 
66
  foreach (array('head', 'body') as $docLocationTag) {
67
  $combinedUriPathsGroup = $localAssetsPathsGroup = $linkHrefsGroup = array();
68
+ $localAssetsExtraGroup = array();
69
+
70
+ $docLocationElements = $domTag->getElementsByTagName($docLocationTag)->item(0);
71
 
 
72
  if ($docLocationElements === null) { continue; }
73
 
74
+ $xpath = new \DOMXpath($domTag);
75
+ $linkTags = $xpath->query('/html/'.$docLocationTag.'/link[@rel="stylesheet"] | /html/'.$docLocationTag.'/link[@rel="preload"]');
76
  if ($linkTags === null) { continue; }
77
 
78
  foreach ($linkTags as $tagObject) {
84
  if (isset($linkAttributes['rel'], $linkAttributes['href']) && $linkAttributes['href']) {
85
  $href = (string) $linkAttributes['href'];
86
 
87
+ // Separate each combined group by the "media" attribute; e.g. we don't want "all" and "print" mixed
88
+ $mediaValue = (array_key_exists('media', $linkAttributes) && $linkAttributes['media']) ? $linkAttributes['media'] : 'all';
89
 
90
+ // Check if there is any rel="preload" (Basic) connected to the rel="stylesheet"
91
+ // making sure the file is not added to the final CSS combined file
92
+ if (isset($linkAttributes['data-wpacu-style-handle']) &&
93
+ $linkAttributes['data-wpacu-style-handle'] &&
94
+ ObjectCache::wpacu_cache_get($linkAttributes['data-wpacu-style-handle'], 'wpacu_basic_preload_handles')) {
95
+ $mediaValue = 'wpacu_preload_basic_' . $mediaValue;
96
  }
97
 
98
+ // Check if the CSS file has any 'data-wpacu-skip' attribute; if it does, do not alter it
99
+ if (isset($linkAttributes['data-wpacu-skip'])) {
100
+ continue;
101
+ }
102
 
103
  if (self::skipCombine($linkAttributes['href'])) {
104
  continue;
105
  }
106
 
107
+ // Make the right reference for later use
108
+ if ($linkAttributes['rel'] === 'preload') {
109
+ if (isset($linkAttributes['data-wpacu-preload-css-basic'])) {
110
+ $mediaValue = 'wpacu_preload_basic_' . $mediaValue;
111
+ } else {
112
+ continue;
113
+ }
114
+ }
115
+
116
  // Was it optimized and has the URL updated? Check the Source URL to determine if it should be skipped from combining
117
  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'])) {
118
  continue;
127
 
128
  // It will skip external stylesheets (from a different domain)
129
  if ( $localAssetPath ) {
130
+ $styleExtra = array();
131
+
132
+ if (isset($linkAttributes['data-wpacu-style-handle'], $wpacuRegisteredStyles[$linkAttributes['data-wpacu-style-handle']]->extra)) {
133
+ $styleExtra = $wpacuRegisteredStyles[$linkAttributes['data-wpacu-style-handle']]->extra;
134
+ }
135
+
136
  $combinedUriPathsGroup[$mediaValue][] = OptimizeCommon::getSourceRelPath($href);
137
  $localAssetsPathsGroup[$mediaValue][$href] = $localAssetPath;
138
  $linkHrefsGroup[$mediaValue][] = $href;
139
+ $localAssetsExtraGroup[$mediaValue][$href] = $styleExtra;
140
  }
141
  }
142
  }
154
 
155
  $localAssetsPaths = $localAssetsPathsGroup[$mediaValue];
156
  $linkHrefs = $linkHrefsGroup[$mediaValue];
157
+ $localAssetsExtra = array_filter($localAssetsExtraGroup[$mediaValue]);
158
 
159
+ $shaOneForCombinedCss = self::generateShaOneForCombinedCss($combinedUriPaths, $localAssetsExtra);
160
 
161
  $maybeDoCssCombine = self::maybeDoCssCombine(
162
  $shaOneForCombinedCss,
163
  $localAssetsPaths, $linkHrefs,
164
+ $localAssetsExtra,
165
  $docLocationTag
166
  );
167
 
225
  $finalTagUrl = OptimizeCommon::filterWpContentUrl($cdnUrlForCss) . OptimizeCss::getRelPathCssCacheDir() . $storageJsonContentLocation['uri_to_final_css_file'];
226
 
227
  $finalCssTagAttrs = array();
 
 
228
 
229
+ if (strpos($mediaValue, 'wpacu_preload_basic_') === 0) {
230
+ // Put the right "media" value after cleaning the reference
231
+ $mediaValueClean = str_replace('wpacu_preload_basic_', '', $mediaValue);
232
+
233
+ // Basic Preload
234
+ $finalCssTag = <<<HTML
235
+ <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}' />
236
+ HTML;
237
+ $finalCssTagRelPreload = <<<HTML
238
+ <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}' />
239
+ HTML;
240
+
241
+ $finalCssTagAttrs['rel'] = 'preload';
242
+ $finalCssTagAttrs['media'] = $mediaValueClean;
243
+
244
+ $htmlSource = str_replace(Preloads::DEL_STYLES_PRELOADS, $finalCssTagRelPreload."\n" . Preloads::DEL_STYLES_PRELOADS, $htmlSource);
245
+ } else {
246
+ // Render-blocking CSS
247
+ $finalCssTag = <<<HTML
248
  <link rel='stylesheet' id='wpacu-combined-css-{$docLocationTag}-{$groupLocation}' href='{$finalTagUrl}' type='text/css' media='{$mediaValue}' />
249
  HTML;
250
+ $finalCssTagAttrs['rel'] = 'stylesheet';
251
+ $finalCssTagAttrs['media'] = $mediaValue;
252
+ }
253
+
254
  // In case one (e.g. usually a developer) needs to alter it
255
  $finalCssTag = apply_filters(
256
  'wpacu_combined_css_tag',
263
  )
264
  );
265
 
266
+ // Reference: https://stackoverflow.com/questions/2368539/php-replacing-multiple-spaces-with-a-single-space
267
+ $finalCssTag = preg_replace('!\s+!', ' ', $finalCssTag);
268
+
269
  $htmlSourceBeforeAnyLinkTagReplacement = $htmlSource;
270
 
271
  // Detect first LINK tag from the <$locationTag> and replace it with the final combined LINK tag
272
  $firstLinkTag = OptimizeCss::getFirstLinkTag($storageJsonContentLocation['link_hrefs'][0], $htmlSource);
273
 
274
  if ($firstLinkTag) {
275
+ // This will also strip the tag (not just the inline code before/after it)
276
+ $htmlSource = self::maybeStripExtraInlineAfterAppended($firstLinkTag, $wpacuRegisteredStyles, $finalCssTag, $htmlSource);
277
  }
278
 
279
  if ($htmlSource !== $htmlSourceBeforeAnyLinkTagReplacement) {
280
  $htmlSource = self::stripJustCombinedLinkTags(
281
  $storageJsonContentLocation['link_hrefs'],
282
+ $wpacuRegisteredStyles,
283
  $htmlSource
284
  ); // Strip the combined files to avoid duplicate code
285
 
300
 
301
  /**
302
  * @param $filesSources
303
+ * @param $wpacuRegisteredStyles
304
  * @param $htmlSource
305
  *
306
  * @return mixed
307
  */
308
+ public static function stripJustCombinedLinkTags($filesSources, $wpacuRegisteredStyles, $htmlSource)
309
  {
310
  preg_match_all('#<link[^>]*(stylesheet|preload)[^>]*(>)#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
311
 
325
  $domTag->loadHTML($matchedSourceFromTag);
326
 
327
  foreach ($domTag->getElementsByTagName('link') as $tagObject) {
328
+ if (empty($tagObject->attributes)) { continue; }
329
 
330
  foreach ($tagObject->attributes as $tagAttrs) {
331
  if ($tagAttrs->nodeName === 'href') {
334
  if (in_array($relNodeValue, $filesSources)) {
335
  $htmlSourceBeforeLinkTagReplacement = $htmlSource;
336
 
337
+ $htmlSource = self::maybeStripExtraInlineAfterAppended($matchedSourceFromTag, $wpacuRegisteredStyles, '', $htmlSource);
338
 
339
  if ($htmlSource !== $htmlSourceBeforeLinkTagReplacement) {
340
  $linkTagsStrippedNo++;
399
  * @param $shaOneForCombinedCss
400
  * @param $localAssetsPaths
401
  * @param $linkHrefs
402
+ * @param $localAssetsExtra
403
  * @param $docLocationTag
404
  *
405
  * @return array
406
  */
407
+ public static function maybeDoCssCombine($shaOneForCombinedCss, $localAssetsPaths, $linkHrefs, $localAssetsExtra, $docLocationTag)
408
  {
409
+ $uriToFinalCssFile = $docLocationTag . '-' .$shaOneForCombinedCss . '.css';
410
+ $localFinalCssFile = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir() . $uriToFinalCssFile;
 
 
 
 
 
411
 
412
  // Only combine if $shaOneCombinedUriPaths.css does not exist
413
  // If "?ver" value changes on any of the assets or the asset list changes in any way
429
 
430
  $finalCombinedCssContent .= '/*! '.str_replace(ABSPATH, '/', $localAssetsPath)." */\n";
431
  $finalCombinedCssContent .= OptimizeCss::maybeFixCssContent($cssContent, $pathToAssetDir . '/') . "\n";
432
+
433
+ $finalCombinedCssContent = self::appendToCombineCss($localAssetsExtra, $assetHref, $pathToAssetDir, $finalCombinedCssContent);
434
  }
435
  }
436
 
441
  $finalCombinedCssContent = FontsGoogleRemove::cleanFontFaceReferences($finalCombinedCssContent);
442
  }
443
 
444
+ $finalCombinedCssContent = apply_filters('wpacu_local_fonts_display_css_output', $finalCombinedCssContent, Main::instance()->settings['local_fonts_display']);
 
 
 
 
 
 
 
445
 
446
+ if ($finalCombinedCssContent) {
447
  FileSystem::file_put_contents($localFinalCssFile, $finalCombinedCssContent);
448
  }
449
  }
457
 
458
  /**
459
  * @param $combinedUriPaths
460
+ * @param $localAssetsExtra
461
  *
462
  * @return string
463
  */
464
+ public static function generateShaOneForCombinedCss($combinedUriPaths, $localAssetsExtra)
465
  {
466
+ $finalShaOneContent = implode('', $combinedUriPaths);
467
+
468
+ // If it is not empty, it means " Add inline tag contents associated with a style (handle) to the combined group of files after the main style's contents"
469
+ // is turned ON within "Combine loaded CSS (Stylesheets) into fewer files" (inside "Settings" -> "Optimize CSS")
470
+ if ( ! empty($localAssetsExtra) ) {
471
+ $afterContentForAll = '';
472
+
473
+ foreach ($localAssetsExtra as $values) {
474
+ if (isset($values['after']) && $values['after']) {
475
+ $afterContentForAll .= $values['after'];
476
+ }
477
+ }
478
+
479
+ $finalShaOneContent .= $afterContentForAll;
480
+ }
481
+
482
+ return sha1($finalShaOneContent);
483
+ }
484
+
485
+ /**
486
+ * @param $localAssetsExtra
487
+ * @param $assetHref
488
+ * @param $pathToAssetDir
489
+ * @param $finalAssetsContents
490
+ *
491
+ * @return string
492
+ */
493
+ public static function appendToCombineCss($localAssetsExtra, $assetHref, $pathToAssetDir, $finalAssetsContents)
494
+ {
495
+ if (isset($localAssetsExtra[$assetHref]['after']) && ! empty($localAssetsExtra[$assetHref]['after'])) {
496
+ $afterCssContent = '';
497
+
498
+ foreach ($localAssetsExtra[$assetHref]['after'] as $afterData) {
499
+ if (! is_bool($afterData)) {
500
+ $afterCssContent .= $afterData."\n";
501
+ }
502
+ }
503
+
504
+ if (trim($afterCssContent) && Main::instance()->settings['minify_loaded_css'] && Main::instance()->settings['minify_loaded_css_inline']) {
505
+ $afterCssContent = MinifyCss::applyMinification($afterCssContent);
506
+ }
507
+
508
+ $afterCssContent = OptimizeCss::maybeFixCssContent($afterCssContent, $pathToAssetDir . '/');
509
+
510
+ $finalAssetsContents .= '/* [inline: after] */'.$afterCssContent.'/* [/inline: after] */'."\n";
511
+ }
512
+
513
+ return $finalAssetsContents;
514
+ }
515
+
516
+ /**
517
+ * The targeted LINK tag (which was enqueued and has a handle) is replaced with $replaceWith
518
+ * along with any inline content that was added after it via wp_add_inline_style()
519
+ *
520
+ * @param $targetedLinkTag
521
+ * @param $wpacuRegisteredStyles
522
+ * @param $replaceWith
523
+ * @param $htmlSource
524
+ *
525
+ * @return mixed
526
+ */
527
+ public static function maybeStripExtraInlineAfterAppended($targetedLinkTag, $wpacuRegisteredStyles, $replaceWith, $htmlSource)
528
+ {
529
+ $scriptExtrasHtml = OptimizeCss::getInlineAssociatedWithLinkHandle($targetedLinkTag, $wpacuRegisteredStyles, 'tag', 'html');
530
+ $scriptExtraAfterHtml = (isset($scriptExtrasHtml['after']) && $scriptExtrasHtml['after']) ? "\n".$scriptExtrasHtml['after'] : '';
531
+
532
+
533
+ if ($scriptExtraAfterHtml) {
534
+ $htmlSource = str_replace(
535
+ array(
536
+ $targetedLinkTag . $scriptExtraAfterHtml,
537
+ $targetedLinkTag . trim($scriptExtraAfterHtml)
538
+ ),
539
+ $replaceWith,
540
+ $htmlSource
541
+ );
542
+ } else {
543
+ $htmlSource = str_replace(
544
+ array(
545
+ $targetedLinkTag."\n",
546
+ $targetedLinkTag
547
+ ),
548
+ $replaceWith."\n",
549
+ $htmlSource
550
+ );
551
+ }
552
+
553
+ return $htmlSource;
554
  }
555
 
556
  /**
classes/OptimiseAssets/CombineCssImports.php CHANGED
@@ -3,7 +3,6 @@ namespace WpAssetCleanUp\OptimiseAssets;
3
 
4
  use MatthiasMullie\Minify\Minify;
5
 
6
- use MatthiasMullie\Minify\Exceptions\FileImportException;
7
  use MatthiasMullie\PathConverter\ConverterInterface;
8
  use MatthiasMullie\PathConverter\Converter;
9
 
@@ -103,7 +102,6 @@ class CombineCssImports extends Minify
103
  *
104
  * @return string
105
  *
106
- * @throws FileImportException
107
  */
108
  protected function combineImports($source, $content, $parents)
109
  {
3
 
4
  use MatthiasMullie\Minify\Minify;
5
 
 
6
  use MatthiasMullie\PathConverter\ConverterInterface;
7
  use MatthiasMullie\PathConverter\Converter;
8
 
102
  *
103
  * @return string
104
  *
 
105
  */
106
  protected function combineImports($source, $content, $parents)
107
  {
classes/OptimiseAssets/CombineJs.php CHANGED
@@ -5,6 +5,7 @@ use WpAssetCleanUp\Main;
5
  use WpAssetCleanUp\Menu;
6
  use WpAssetCleanUp\FileSystem;
7
  use WpAssetCleanUp\Misc;
 
8
 
9
  /**
10
  * Class CombineJs
@@ -24,7 +25,7 @@ class CombineJs
24
  */
25
  public static function doCombine($htmlSource)
26
  {
27
- if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('DOMDocument'))) {
28
  return $htmlSource;
29
  }
30
 
@@ -32,12 +33,12 @@ class CombineJs
32
  return $htmlSource;
33
  }
34
 
35
- /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_combine_js'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
36
-
37
 
38
  $combineLevel = 2;
39
 
40
- $isDeferAppliedOnBodyCombineGroupNo = 0;
41
 
42
  // Speed up processing by getting the already existing final CSS file URI
43
  // This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
@@ -46,62 +47,101 @@ class CombineJs
46
  // $uriToFinalJsFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathJsCacheDir()
47
  // which is usually "wp-content/cache/asset-cleanup/js/"
48
 
49
- // "false" would make it avoid checking the cache and always use the DOM Parser / RegExp
50
  // for DEV purposes ONLY as it uses more resources
51
- if (empty($finalCacheList)) {
 
 
 
 
 
 
52
  /*
53
  * NO CACHING TRANSIENT; Parse the DOM
54
  */
55
  // Nothing in the database records or the retrieved cached file does not exist?
56
  OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
57
 
58
- // Fetch the DOM
59
- $documentForJS = new \DOMDocument();
60
- libxml_use_internal_errors(true);
61
-
62
  $combinableList = array();
63
 
64
  $jQueryMigrateInBody = false;
65
  $jQueryLibInBodyCount = 0;
66
 
67
- // Strip NOSCRIPT tags
68
- $htmlSourceAlt = preg_replace('@<(noscript)[^>]*?>.*?</\\1>@si', '', $htmlSource);
69
- $documentForJS->loadHTML($htmlSourceAlt);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  // Only keep combinable JS files
72
  foreach ( array( 'head', 'body' ) as $docLocationScript ) {
73
  $groupIndex = 1;
74
 
75
- $docLocationElements = $documentForJS->getElementsByTagName($docLocationScript)->item(0);
76
  if ($docLocationElements === null) { continue; }
77
 
78
  // High accuracy (e.g. it ignores tags inside HTML comments, conditional or not)
79
  $scriptTags = $docLocationElements->getElementsByTagName('script');
80
  if ($scriptTags === null) { continue; }
81
 
82
- foreach ($scriptTags as $scriptTagIndex => $tagObject) {
83
- if (! $tagObject->hasAttributes()) { continue; }
 
84
 
 
85
  $scriptAttributes = array();
86
 
87
- foreach ($tagObject->attributes as $attrObj) {
88
- $scriptAttributes[$attrObj->nodeName] = trim($attrObj->nodeValue);
 
 
89
  }
90
 
91
- $scriptNotCombinable = false;
 
 
 
 
 
92
 
93
  $hasSrc = isset($scriptAttributes['src']) && trim($scriptAttributes['src']); // No valid SRC attribute? It's not combinable (e.g. an inline tag)
94
  $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)
95
 
96
- if (! $hasSrc || $isPluginScript) {
97
  // Inline tag? Skip it in the BODY
98
  if ($docLocationScript === 'body') {
99
  continue;
100
  }
101
 
102
  // Because of jQuery, we will not have the list of all inline scripts and then the combined files as it is in BODY
103
- // Once an inline SCRIPT is stumbled upon, a new combined group in the HEAD tag will be formed
104
  if ($docLocationScript === 'head') {
 
 
 
 
 
 
 
 
 
 
 
 
105
  $scriptNotCombinable = true;
106
  }
107
  }
@@ -109,7 +149,8 @@ class CombineJs
109
  $isInGroupType = 'standard';
110
  $isJQueryLib = $isJQueryMigrate = false;
111
 
112
- if (! $scriptNotCombinable) { // Has SRC and $isPluginScript is set to false? Check the script
 
113
  $src = (string)$scriptAttributes['src'];
114
 
115
  if (self::skipCombine($src)) {
@@ -145,6 +186,12 @@ class CombineJs
145
  if ( ! $scriptNotCombinable ) {
146
  // It also checks the domain name to make sure no external scripts would be added to the list
147
  if ( $localAssetPath = OptimizeCommon::getLocalAssetPath( $src, 'js' ) ) {
 
 
 
 
 
 
148
  // Standard (could be multiple groups per $docLocationScript), Async & Defer, Async, Defer
149
  $groupByType = ($isInGroupType === 'standard') ? $groupIndex : $isInGroupType;
150
 
@@ -165,7 +212,8 @@ class CombineJs
165
  'info' => array(
166
  'is_jquery' => $isJQueryLib,
167
  'is_jquery_migrate' => $isJQueryMigrate
168
- )
 
169
  );
170
 
171
  if ($docLocationScript === 'body' && $jQueryLibInBodyCount === 2) {
@@ -198,6 +246,7 @@ class CombineJs
198
  }
199
 
200
  $combinedUriPaths = $localAssetsPaths = $groupScriptSrcs = array();
 
201
  $jQueryIsIncludedInGroup = false;
202
 
203
  foreach ($groupFiles as $groupFileData) {
@@ -215,6 +264,7 @@ class CombineJs
215
  $groupScriptSrcs[] = $src;
216
  $combinedUriPaths[] = OptimizeCommon::getSourceRelPath($src);
217
  $localAssetsPaths[$src] = $groupFileData['local'];
 
218
  }
219
 
220
  $shaOneForCombinedJs = self::generateShaOneForCombinedJs($combinedUriPaths, $localAssetsExtra);
@@ -222,6 +272,7 @@ class CombineJs
222
  $maybeDoJsCombine = self::maybeDoJsCombine(
223
  $shaOneForCombinedJs . '-' . $groupNo,
224
  $localAssetsPaths,
 
225
  $docLocationScript
226
  );
227
 
@@ -261,7 +312,7 @@ class CombineJs
261
 
262
  // Apply defer="defer" to combined JS files from the BODY tag (if enabled), except the combined jQuery & jQuery Migrate Group
263
  if ($docLocationScript === 'body' && ! $jQueryIsIncludedInGroup && Main::instance()->settings['combine_loaded_js_defer_body']) {
264
- if ($isDeferAppliedOnBodyCombineGroupNo === 0) {
265
  // Only record the first one
266
  $isDeferAppliedOnBodyCombineGroupNo = $groupNo;
267
  }
@@ -327,7 +378,7 @@ HTML;
327
  $replaceWith = ($groupScriptTagIndex === $indexReplacement) ? $finalJsTag : '';
328
  $htmlSourceBeforeTagReplacement = $htmlSource;
329
 
330
- $htmlSource = OptimizeJs::strReplaceOnce($scriptTag, $replaceWith, $htmlSource);
331
 
332
  if ($htmlSource !== $htmlSourceBeforeTagReplacement) {
333
  $scriptTagsStrippedNo ++;
@@ -339,40 +390,71 @@ HTML;
339
  if (count($filesSources) !== $scriptTagsStrippedNo) {
340
  $htmlSource = $htmlSourceBeforeGroupReplacement;
341
  }
342
-
343
- }
344
  }
345
  }
346
 
347
  // Only relevant if "Defer loading JavaScript combined files from <body>"" in "Settings" - "Combine CSS & JS Files" - "Combine loaded JS (JavaScript) into fewer files"
348
  // and there is at least one combined deferred tag
349
- if ($isDeferAppliedOnBodyCombineGroupNo > 0) {
350
- $strPart = "id='wpacu-combined-js-body-group-".$isDeferAppliedOnBodyCombineGroupNo."' type='text/javascript' ";
351
- list(,$htmlAfterFirstCombinedDeferScript) = explode($strPart, $htmlSource);
352
- $htmlAfterFirstCombinedDeferScriptMaybeChanged = $htmlAfterFirstCombinedDeferScript;
353
 
354
- $documentForPartBodyHtml = new \DOMDocument();
355
- libxml_use_internal_errors(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
 
357
- $documentForPartBodyHtml->loadHTML($htmlSource);
 
358
 
359
- $scriptTags = $documentForPartBodyHtml->getElementsByTagName('script');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
- // No other SCRIPT tags found after the first (maybe last) deferred combined tag? Just return the HTML source
362
- if ($scriptTags === null) {
363
- libxml_clear_errors();
364
  return $htmlSource;
365
  }
366
 
367
  foreach ($scriptTags as $scriptTagIndex => $tagObject) {
368
- if (! $tagObject->hasAttributes()) {
369
- continue;
370
- }
371
 
372
  $scriptAttributes = array();
373
 
374
- foreach ($tagObject->attributes as $attrObj) {
375
- $scriptAttributes[$attrObj->nodeName] = trim($attrObj->nodeValue);
376
  }
377
 
378
  // No "src" attribute? Skip it (most likely an inline script tag)
@@ -400,8 +482,6 @@ HTML;
400
 
401
  libxml_clear_errors();
402
 
403
- /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
404
-
405
  // Finally, return the HTML source
406
  return $htmlSource;
407
  }
@@ -447,24 +527,19 @@ HTML;
447
  /**
448
  * @param $shaOneForCombinedJs
449
  * @param $localAssetsPaths
 
450
  * @param $docLocationScript
451
  *
452
  * @return array
453
  */
454
- public static function maybeDoJsCombine($shaOneForCombinedJs, $localAssetsPaths, $docLocationScript)
455
  {
456
- $current_user = wp_get_current_user();
457
- $dirToUserCachedFile = ((isset($current_user->ID) && $current_user->ID > 0) ? 'logged-in/' : '');
458
-
459
- $uriToFinalJsFile = $dirToUserCachedFile . $docLocationScript . '-' . $shaOneForCombinedJs . '.js';
460
-
461
  $localFinalJsFile = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir() . $uriToFinalJsFile;
462
- $localDirForJsFile = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir() . $dirToUserCachedFile;
463
 
464
  // Only combine if $shaOneCombinedUriPaths.js does not exist
465
  // If "?ver" value changes on any of the assets or the asset list changes in any way
466
  // then $shaOneCombinedUriPaths will change too and a new JS file will be generated and loaded
467
-
468
  $skipIfFileExists = true;
469
 
470
  if ($skipIfFileExists || ! is_file($localFinalJsFile)) {
@@ -484,23 +559,18 @@ HTML;
484
 
485
  $pathToAssetDir = OptimizeCommon::getPathToAssetDir($assetHref);
486
 
487
- $contentToAddToCombinedFile = '/*! '.str_replace(ABSPATH, '/', $localAssetsPath)." */\n";
488
 
 
 
489
  $contentToAddToCombinedFile .= OptimizeJs::maybeDoJsFixes($jsContent, $pathToAssetDir . '/') . "\n";
 
490
 
491
  $finalJsContents .= $contentToAddToCombinedFile;
492
  }
493
  }
494
 
495
  if ($finalJsContents !== '') {
496
- if ($dirToUserCachedFile !== '' && isset($current_user->ID) && $current_user->ID > 0 && ! is_dir($localDirForJsFile)) {
497
- $makeLocalDirForJs = @mkdir($localDirForJsFile);
498
-
499
- if (! $makeLocalDirForJs) {
500
- return array('uri_final_js_file' => '', 'local_final_js_file' => '');
501
- }
502
- }
503
-
504
  FileSystem::file_put_contents($localFinalJsFile, $finalJsContents);
505
  }
506
  }
@@ -519,7 +589,130 @@ HTML;
519
  */
520
  public static function generateShaOneForCombinedJs($combinedUriPaths, $localAssetsExtra)
521
  {
522
- return sha1(implode('', $combinedUriPaths));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  }
524
 
525
  /**
5
  use WpAssetCleanUp\Menu;
6
  use WpAssetCleanUp\FileSystem;
7
  use WpAssetCleanUp\Misc;
8
+ use WpAssetCleanUp\ObjectCache;
9
 
10
  /**
11
  * Class CombineJs
25
  */
26
  public static function doCombine($htmlSource)
27
  {
28
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument'))) {
29
  return $htmlSource;
30
  }
31
 
33
  return $htmlSource;
34
  }
35
 
36
+ global $wp_scripts;
37
+ $wpacuRegisteredScripts = $wp_scripts->registered;
38
 
39
  $combineLevel = 2;
40
 
41
+ $isDeferAppliedOnBodyCombineGroupNo = false;
42
 
43
  // Speed up processing by getting the already existing final CSS file URI
44
  // This will avoid parsing the HTML DOM and determine the combined URI paths for all the CSS files
47
  // $uriToFinalJsFile will always be relative ONLY within WP_CONTENT_DIR . self::getRelPathJsCacheDir()
48
  // which is usually "wp-content/cache/asset-cleanup/js/"
49
 
50
+ // "true" would make it avoid checking the cache and always use the DOM Parser / RegExp
51
  // for DEV purposes ONLY as it uses more resources
52
+ $skipCache = false;
53
+
54
+ if (isset($_GET['wpacu_no_cache'])) {
55
+ $skipCache = true;
56
+ }
57
+
58
+ if ( $skipCache || empty($finalCacheList) ) {
59
  /*
60
  * NO CACHING TRANSIENT; Parse the DOM
61
  */
62
  // Nothing in the database records or the retrieved cached file does not exist?
63
  OptimizeCommon::clearAssetCachedData(self::$jsonStorageFile);
64
 
 
 
 
 
65
  $combinableList = array();
66
 
67
  $jQueryMigrateInBody = false;
68
  $jQueryLibInBodyCount = 0;
69
 
70
+ $minifyJsInlineTagsIsNotEnabled = ! (MinifyJs::isMinifyJsEnabled() && Main::instance()->settings['minify_loaded_js_inline']);
71
+
72
+ if ($minifyJsInlineTagsIsNotEnabled) {
73
+ $domTag = new \DOMDocument();
74
+ libxml_use_internal_errors(true);
75
+
76
+ // Strip irrelevant tags to boost the speed of the parser (e.g. NOSCRIPT / SCRIPT(inline) / STYLE)
77
+ // Sometimes, inline CODE can be too large and it takes extra time for loadHTML() to parse
78
+ $htmlSourceAlt = preg_replace( '@<script(| (type=(\'|"|)text/(javascript|template|html)(\'|"|)))>.*?</script>@si', '', $htmlSource );
79
+ $htmlSourceAlt = preg_replace( '@<(style|noscript)[^>]*?>.*?</\\1>@si', '', $htmlSourceAlt );
80
+ $htmlSourceAlt = preg_replace( '#<link([^<>]+)/?>#iU', '', $htmlSourceAlt );
81
+
82
+ if (Main::instance()->isFrontendEditView) {
83
+ $htmlSourceAlt = preg_replace( '@<form action="#wpacu_wrap_assets" method="post">.*?</form>@si', '', $htmlSourceAlt );
84
+ }
85
+
86
+ $domTag->loadHTML( $htmlSourceAlt );
87
+ } else {
88
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'combineJs');
89
+ }
90
 
91
  // Only keep combinable JS files
92
  foreach ( array( 'head', 'body' ) as $docLocationScript ) {
93
  $groupIndex = 1;
94
 
95
+ $docLocationElements = $domTag->getElementsByTagName($docLocationScript)->item(0);
96
  if ($docLocationElements === null) { continue; }
97
 
98
  // High accuracy (e.g. it ignores tags inside HTML comments, conditional or not)
99
  $scriptTags = $docLocationElements->getElementsByTagName('script');
100
  if ($scriptTags === null) { continue; }
101
 
102
+ if ($docLocationScript && Main::instance()->settings['combine_loaded_js_defer_body']) {
103
+ ObjectCache::wpacu_cache_set('wpacu_html_dom_body_tag_for_js', $docLocationElements);
104
+ }
105
 
106
+ foreach ($scriptTags as $scriptTagIndex => $tagObject) {
107
  $scriptAttributes = array();
108
 
109
+ if ( isset($tagObject->attributes) && ! empty($tagObject->attributes) ) {
110
+ foreach ( $tagObject->attributes as $attrObj ) {
111
+ $scriptAttributes[ $attrObj->nodeName ] = trim( $attrObj->nodeValue );
112
+ }
113
  }
114
 
115
+ $scriptNotCombinable = false; // default (usually, most of the SCRIPT tags can be optimized)
116
+
117
+ // Check if the CSS file has any 'data-wpacu-skip' attribute; if it does, do not alter it
118
+ if (isset($scriptAttributes['data-wpacu-skip'])) {
119
+ $scriptNotCombinable = true;
120
+ }
121
 
122
  $hasSrc = isset($scriptAttributes['src']) && trim($scriptAttributes['src']); // No valid SRC attribute? It's not combinable (e.g. an inline tag)
123
  $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)
124
 
125
+ if (! $scriptNotCombinable && (! $hasSrc || $isPluginScript)) {
126
  // Inline tag? Skip it in the BODY
127
  if ($docLocationScript === 'body') {
128
  continue;
129
  }
130
 
131
  // Because of jQuery, we will not have the list of all inline scripts and then the combined files as it is in BODY
 
132
  if ($docLocationScript === 'head') {
133
+ // 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
134
+ if (isset($scriptAttributes['data-wpacu-script-handle']) && $scriptAttributes['data-wpacu-script-handle']) {
135
+ $getInlineAssociatedWithHandle = OptimizeJs::getInlineAssociatedWithScriptHandle($scriptAttributes['data-wpacu-script-handle'], $wpacuRegisteredScripts, 'handle');
136
+
137
+ if ( in_array(trim($tagObject->nodeValue), array($getInlineAssociatedWithHandle['before'], $getInlineAssociatedWithHandle['after']))
138
+ || (strpos(trim($tagObject->nodeValue), '/* <![CDATA[ */') === 0 && Misc::endsWith(trim($tagObject->nodeValue), '/* ]]> */')) ) {
139
+ // It's associated with the enqueued scripts or it's a (standalone) CDATA inline tag added via wp_localize_script()
140
+ // 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
141
+ continue;
142
+ }
143
+ }
144
+
145
  $scriptNotCombinable = true;
146
  }
147
  }
149
  $isInGroupType = 'standard';
150
  $isJQueryLib = $isJQueryMigrate = false;
151
 
152
+ // Has SRC and $isPluginScript is set to false OR it does not have "data-wpacu-skip" attribute
153
+ if (! $scriptNotCombinable) {
154
  $src = (string)$scriptAttributes['src'];
155
 
156
  if (self::skipCombine($src)) {
186
  if ( ! $scriptNotCombinable ) {
187
  // It also checks the domain name to make sure no external scripts would be added to the list
188
  if ( $localAssetPath = OptimizeCommon::getLocalAssetPath( $src, 'js' ) ) {
189
+ $scriptExtra = array();
190
+
191
+ if (isset($scriptAttributes['data-wpacu-script-handle'], $wpacuRegisteredScripts[$scriptAttributes['data-wpacu-script-handle']]->extra)) {
192
+ $scriptExtra = $wpacuRegisteredScripts[$scriptAttributes['data-wpacu-script-handle']]->extra;
193
+ }
194
+
195
  // Standard (could be multiple groups per $docLocationScript), Async & Defer, Async, Defer
196
  $groupByType = ($isInGroupType === 'standard') ? $groupIndex : $isInGroupType;
197
 
212
  'info' => array(
213
  'is_jquery' => $isJQueryLib,
214
  'is_jquery_migrate' => $isJQueryMigrate
215
+ ),
216
+ 'extra' => $scriptExtra
217
  );
218
 
219
  if ($docLocationScript === 'body' && $jQueryLibInBodyCount === 2) {
246
  }
247
 
248
  $combinedUriPaths = $localAssetsPaths = $groupScriptSrcs = array();
249
+ $localAssetsExtra = array();
250
  $jQueryIsIncludedInGroup = false;
251
 
252
  foreach ($groupFiles as $groupFileData) {
264
  $groupScriptSrcs[] = $src;
265
  $combinedUriPaths[] = OptimizeCommon::getSourceRelPath($src);
266
  $localAssetsPaths[$src] = $groupFileData['local'];
267
+ $localAssetsExtra[$src] = $groupFileData['extra'];
268
  }
269
 
270
  $shaOneForCombinedJs = self::generateShaOneForCombinedJs($combinedUriPaths, $localAssetsExtra);
272
  $maybeDoJsCombine = self::maybeDoJsCombine(
273
  $shaOneForCombinedJs . '-' . $groupNo,
274
  $localAssetsPaths,
275
+ $localAssetsExtra,
276
  $docLocationScript
277
  );
278
 
312
 
313
  // Apply defer="defer" to combined JS files from the BODY tag (if enabled), except the combined jQuery & jQuery Migrate Group
314
  if ($docLocationScript === 'body' && ! $jQueryIsIncludedInGroup && Main::instance()->settings['combine_loaded_js_defer_body']) {
315
+ if ($isDeferAppliedOnBodyCombineGroupNo === false) {
316
  // Only record the first one
317
  $isDeferAppliedOnBodyCombineGroupNo = $groupNo;
318
  }
378
  $replaceWith = ($groupScriptTagIndex === $indexReplacement) ? $finalJsTag : '';
379
  $htmlSourceBeforeTagReplacement = $htmlSource;
380
 
381
+ $htmlSource = self::maybeStripExtraInlineAfterAppended($scriptTag, $wpacuRegisteredScripts, $replaceWith, $htmlSource);
382
 
383
  if ($htmlSource !== $htmlSourceBeforeTagReplacement) {
384
  $scriptTagsStrippedNo ++;
390
  if (count($filesSources) !== $scriptTagsStrippedNo) {
391
  $htmlSource = $htmlSourceBeforeGroupReplacement;
392
  }
393
+ }
 
394
  }
395
  }
396
 
397
  // Only relevant if "Defer loading JavaScript combined files from <body>"" in "Settings" - "Combine CSS & JS Files" - "Combine loaded JS (JavaScript) into fewer files"
398
  // and there is at least one combined deferred tag
 
 
 
 
399
 
400
+ if (isset($finalCacheList['body']) && (! empty($finalCacheList['body'])) && Main::instance()->settings['combine_loaded_js_defer_body']) {
401
+ // CACHE RE-BUILT
402
+ if ($isDeferAppliedOnBodyCombineGroupNo > 0 && $domTag = ObjectCache::wpacu_cache_get('wpacu_html_dom_body_tag_for_js')) {
403
+ $strPart = "id='wpacu-combined-js-body-group-".$isDeferAppliedOnBodyCombineGroupNo."' type='text/javascript' ";
404
+ list(,$htmlAfterFirstCombinedDeferScript) = explode($strPart, $htmlSource);
405
+ $htmlAfterFirstCombinedDeferScriptMaybeChanged = $htmlAfterFirstCombinedDeferScript;
406
+ $scriptTags = $domTag->getElementsByTagName('script');
407
+ } else {
408
+ // FROM THE CACHE
409
+ foreach ($finalCacheList['body'] as $bodyCombineGroupNo => $values) {
410
+ if (isset($values['extra_attributes']) && in_array('defer', $values['extra_attributes'])) {
411
+ $isDeferAppliedOnBodyCombineGroupNo = $bodyCombineGroupNo;
412
+ break;
413
+ }
414
+ }
415
+
416
+ if (! $isDeferAppliedOnBodyCombineGroupNo) {
417
+ // Not applicable to any combined group
418
+ return $htmlSource;
419
+ }
420
+
421
+ $strPart = "id='wpacu-combined-js-body-group-".$isDeferAppliedOnBodyCombineGroupNo."' type='text/javascript' ";
422
+ list(,$htmlAfterFirstCombinedDeferScript) = explode($strPart, $htmlSource);
423
+ $htmlAfterFirstCombinedDeferScriptMaybeChanged = $htmlAfterFirstCombinedDeferScript;
424
 
425
+ $domTag = new \DOMDocument();
426
+ libxml_use_internal_errors(true);
427
 
428
+ // Strip irrelevant tags to boost the speed of the parser (e.g. NOSCRIPT / SCRIPT(inline) / STYLE)
429
+ // Sometimes, inline CODE can be too large and it takes extra time for loadHTML() to parse
430
+ $htmlSourceAlt = preg_replace( '@<script(| type=\'text/javascript\'| type="text/javascript")>.*?</script>@si', '', $htmlAfterFirstCombinedDeferScript );
431
+ $htmlSourceAlt = preg_replace( '@<(style|noscript)[^>]*?>.*?</\\1>@si', '', $htmlSourceAlt );
432
+ $htmlSourceAlt = preg_replace( '#<link([^<>]+)/?>#iU', '', $htmlSourceAlt );
433
+
434
+ if (Main::instance()->isFrontendEditView) {
435
+ $htmlSourceAlt = preg_replace( '@<form action="#wpacu_wrap_assets" method="post">.*?</form>@si', '', $htmlSourceAlt );
436
+ }
437
+
438
+ // It could no other SCRIPT left, stop here in this case
439
+ if (strpos($htmlSource, '<script') !== false) {
440
+ return $htmlSource;
441
+ }
442
+
443
+ $domTag->loadHTML( $htmlSourceAlt );
444
+ $scriptTags = $domTag->getElementsByTagName('script');
445
+ }
446
 
447
+ if ( $scriptTags === null ) {
 
 
448
  return $htmlSource;
449
  }
450
 
451
  foreach ($scriptTags as $scriptTagIndex => $tagObject) {
452
+ if (empty($tagObject->attributes)) { continue; }
 
 
453
 
454
  $scriptAttributes = array();
455
 
456
+ foreach ( $tagObject->attributes as $attrObj ) {
457
+ $scriptAttributes[ $attrObj->nodeName ] = trim( $attrObj->nodeValue );
458
  }
459
 
460
  // No "src" attribute? Skip it (most likely an inline script tag)
482
 
483
  libxml_clear_errors();
484
 
 
 
485
  // Finally, return the HTML source
486
  return $htmlSource;
487
  }
527
  /**
528
  * @param $shaOneForCombinedJs
529
  * @param $localAssetsPaths
530
+ * @param $localAssetsExtra
531
  * @param $docLocationScript
532
  *
533
  * @return array
534
  */
535
+ public static function maybeDoJsCombine($shaOneForCombinedJs, $localAssetsPaths, $localAssetsExtra, $docLocationScript)
536
  {
537
+ $uriToFinalJsFile = $docLocationScript . '-' . $shaOneForCombinedJs . '.js';
 
 
 
 
538
  $localFinalJsFile = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir() . $uriToFinalJsFile;
 
539
 
540
  // Only combine if $shaOneCombinedUriPaths.js does not exist
541
  // If "?ver" value changes on any of the assets or the asset list changes in any way
542
  // then $shaOneCombinedUriPaths will change too and a new JS file will be generated and loaded
 
543
  $skipIfFileExists = true;
544
 
545
  if ($skipIfFileExists || ! is_file($localFinalJsFile)) {
559
 
560
  $pathToAssetDir = OptimizeCommon::getPathToAssetDir($assetHref);
561
 
562
+ $contentToAddToCombinedFile = '/*!'.str_replace(ABSPATH, '/', $localAssetsPath)."*/\n";
563
 
564
+ // This includes the extra from 'data' (CDATA added via wp_localize_script()) & 'before' as they are both printed BEFORE the tag
565
+ $contentToAddToCombinedFile .= self::appendToCombineScript('before', $localAssetsExtra, $assetHref, $pathToAssetDir);
566
  $contentToAddToCombinedFile .= OptimizeJs::maybeDoJsFixes($jsContent, $pathToAssetDir . '/') . "\n";
567
+ $contentToAddToCombinedFile .= self::appendToCombineScript('after', $localAssetsExtra, $assetHref, $pathToAssetDir);
568
 
569
  $finalJsContents .= $contentToAddToCombinedFile;
570
  }
571
  }
572
 
573
  if ($finalJsContents !== '') {
 
 
 
 
 
 
 
 
574
  FileSystem::file_put_contents($localFinalJsFile, $finalJsContents);
575
  }
576
  }
589
  */
590
  public static function generateShaOneForCombinedJs($combinedUriPaths, $localAssetsExtra)
591
  {
592
+ $finalShaOneContent = implode('', $combinedUriPaths);
593
+
594
+ // If it is not empty, it means " Add inline tag contents associated with a style (handle) to the combined group of files after the main style's contents"
595
+ // is turned ON within "Combine loaded JS (JavaScript) into fewer files" (inside "Settings" -> "Optimize JavaScript")
596
+ if ( ! empty($localAssetsExtra) ) {
597
+ $afterContentForAll = '';
598
+
599
+ foreach ( $localAssetsExtra as $values ) {
600
+ foreach ( array('data', 'before', 'after') as $keyToCheck ) {
601
+ if ( isset( $values[$keyToCheck] ) && $values[$keyToCheck] ) {
602
+ $afterContentForAll .= $values[$keyToCheck];
603
+ }
604
+ }
605
+ }
606
+
607
+ $finalShaOneContent .= $afterContentForAll;
608
+ }
609
+
610
+ return sha1($finalShaOneContent);
611
+ }
612
+
613
+ /**
614
+ * @param $addItLocation
615
+ * @param $localAssetsExtra
616
+ * @param $assetHref
617
+ * @param $pathToAssetDir
618
+ *
619
+ * @return string
620
+ */
621
+ public static function appendToCombineScript($addItLocation, $localAssetsExtra, $assetHref, $pathToAssetDir)
622
+ {
623
+ $extraContentToAppend = '';
624
+ $doJsMinifyInline = Main::instance()->settings['minify_loaded_js'] && Main::instance()->settings['minify_loaded_js_inline'];
625
+
626
+ if ($addItLocation === 'before') {
627
+ // [Before JS Content]
628
+ if (isset($localAssetsExtra[$assetHref]['data'])) {
629
+ $cData = $doJsMinifyInline
630
+ ? MinifyJs::applyMinification($localAssetsExtra[$assetHref]['data'])
631
+ : $localAssetsExtra[$assetHref]['data'];
632
+ $cData = OptimizeJs::maybeDoJsFixes($cData, $pathToAssetDir . '/');
633
+ $extraContentToAppend .= '/* [inline: cdata] */' . $cData . '/* [/inline: cdata] */' . "\n";
634
+ }
635
+
636
+ if (isset($localAssetsExtra[$assetHref]['before']) && ! empty($localAssetsExtra[$assetHref]['before'])) {
637
+ $inlineBeforeJsData = '';
638
+
639
+ foreach ($localAssetsExtra[$assetHref]['before'] as $beforeData) {
640
+ if (! is_bool($beforeData)) {
641
+ $inlineBeforeJsData .= $beforeData . "\n";
642
+ }
643
+ }
644
+
645
+ $inlineBeforeJsData = OptimizeJs::maybeAlterContentForInlineScriptTag($inlineBeforeJsData, $doJsMinifyInline);
646
+ $inlineBeforeJsData = OptimizeJs::maybeDoJsFixes($inlineBeforeJsData, $pathToAssetDir . '/');
647
+
648
+ $extraContentToAppend .= '/* [inline: before] */' . $inlineBeforeJsData . '/* [/inline: before] */' . "\n";
649
+ }
650
+ // [/Before JS Content]
651
+ } elseif ($addItLocation === 'after') {
652
+ // [After JS Content]
653
+ if (isset($localAssetsExtra[$assetHref]['after']) && ! empty($localAssetsExtra[$assetHref]['after'])) {
654
+ $inlineAfterJsData = '';
655
+
656
+ foreach ($localAssetsExtra[$assetHref]['after'] as $afterData) {
657
+ if (! is_bool($afterData)) {
658
+ $inlineAfterJsData .= $afterData."\n";
659
+ }
660
+ }
661
+
662
+ $inlineAfterJsData = OptimizeJs::maybeAlterContentForInlineScriptTag($inlineAfterJsData, $doJsMinifyInline);
663
+ $inlineAfterJsData = OptimizeJs::maybeDoJsFixes($inlineAfterJsData, $pathToAssetDir . '/');
664
+
665
+ $extraContentToAppend .= '/* [inline: after] */'.$inlineAfterJsData.'/* [/inline: after] */'."\n";
666
+ }
667
+ // [/After JS Content]
668
+ }
669
+
670
+ return $extraContentToAppend;
671
+ }
672
+
673
+ /**
674
+ * @param $scriptTag
675
+ * @param $wpacuRegisteredScripts
676
+ * @param $replaceWith
677
+ * @param $htmlSource
678
+ *
679
+ * @return mixed
680
+ */
681
+ public static function maybeStripExtraInlineAfterAppended($scriptTag, $wpacuRegisteredScripts, $replaceWith, $htmlSource)
682
+ {
683
+ $scriptExtrasValue = OptimizeJs::getInlineAssociatedWithScriptHandle($scriptTag, $wpacuRegisteredScripts, 'tag', 'value');
684
+
685
+ $scriptExtraCdataValue = (isset($scriptExtrasValue['data']) && $scriptExtrasValue['data']) ? $scriptExtrasValue['data'] : '';
686
+ $scriptExtraBeforeValue = (isset($scriptExtrasValue['before']) && $scriptExtrasValue['before']) ? $scriptExtrasValue['before'] : '';
687
+ $scriptExtraAfterValue = (isset($scriptExtrasValue['after']) && $scriptExtrasValue['after']) ? $scriptExtrasValue['after'] : '';
688
+
689
+ $scriptExtrasHtml = OptimizeJs::getInlineAssociatedWithScriptHandle($scriptTag, $wpacuRegisteredScripts, 'tag', 'html');
690
+
691
+ $scriptExtraCdataHtml = (isset($scriptExtrasHtml['data']) && $scriptExtrasHtml['data']) ? $scriptExtrasHtml['data'] : '';
692
+ $scriptExtraBeforeHtml = (isset($scriptExtrasHtml['before']) && $scriptExtrasHtml['before']) ? $scriptExtrasHtml['before'] : '';
693
+ $scriptExtraAfterHtml = (isset($scriptExtrasHtml['after']) && $scriptExtrasHtml['after']) ? $scriptExtrasHtml['after'] : '';
694
+
695
+ if ($scriptExtraCdataValue || $scriptExtraBeforeValue || $scriptExtraAfterValue) {
696
+ if ($scriptExtraCdataValue) {
697
+ $htmlSource = str_replace($scriptExtraCdataHtml, '', $htmlSource );
698
+ }
699
+
700
+ if ($scriptExtraBeforeValue) {
701
+ $repsBefore = array($scriptExtraBeforeHtml => '', '>'."\n".$scriptExtraBeforeValue."\n".'</script>' => '></script>');
702
+ $htmlSource = str_replace(array_keys($repsBefore), array_values($repsBefore), $htmlSource );
703
+ }
704
+
705
+ if ($scriptExtraAfterValue) {
706
+ $repsBefore = array($scriptExtraAfterHtml => '', '>'."\n".$scriptExtraAfterValue."\n".'</script>' => '></script>');
707
+ $htmlSource = str_replace(array_keys($repsBefore), array_values($repsBefore), $htmlSource );
708
+ }
709
+
710
+ $htmlSource = str_replace($scriptTag, $replaceWith, $htmlSource);
711
+ } else {
712
+ $htmlSource = OptimizeJs::strReplaceOnce($scriptTag, $replaceWith, $htmlSource);
713
+ }
714
+
715
+ return $htmlSource;
716
  }
717
 
718
  /**
classes/OptimiseAssets/FontsGoogle.php CHANGED
@@ -47,6 +47,11 @@ class FontsGoogle
47
  echo self::NOSCRIPT_WEB_FONT_LOADER;
48
  }, PHP_INT_MAX);
49
 
 
 
 
 
 
50
  add_action('init', function() {
51
  // don't apply any changes if not in the front-end view (e.g. Dashboard view)
52
  // or test mode is enabled and a guest user is accessing the page
@@ -185,6 +190,11 @@ class FontsGoogle
185
  continue;
186
  }
187
 
 
 
 
 
 
188
  preg_match_all('#href=(["\'])' . '(.*)' . '(["\'])#Usmi', $linkTag, $outputMatches);
189
  $linkHrefOriginal = $finalLinkHref = trim($outputMatches[2][0], '"\'');
190
 
@@ -229,6 +239,8 @@ class FontsGoogle
229
  }
230
  }
231
 
 
 
232
  // Only proceed with the optimization/combine if there's obviously at least 2 combinable URL requests to Google Fonts
233
  // OR the loading type is different than render-blocking
234
  if (Main::instance()->settings['google_fonts_combine'] && (Main::instance()->settings['google_fonts_combine_type'] || count($finalCombinableLinks) > 1)) {
@@ -313,6 +325,11 @@ class FontsGoogle
313
  foreach ($styleMatches as $styleInlineArray) {
314
  list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
315
 
 
 
 
 
 
316
  // Is the content relevant?
317
  if (! preg_match('/@import(\s+|)(url|\(|\'|")/i', $styleInlineContent)
318
  || stripos($styleInlineContent, 'fonts.googleapis.com') === false) {
@@ -600,18 +617,14 @@ HTML;
600
 
601
  // Any types? e.g. 400, 400italic, bold, etc.
602
  $hasTypes = false;
603
- if (isset($fontValues['types']) && is_array($fontValues['types']) && ! empty($fontValues['types'])) {
604
- $wfConfigGoogleFamily .= ':' . implode(',', $fontValues['types']);
605
  $hasTypes = true;
606
  }
607
 
608
  if ($subSetsStr) {
609
- // No type and has a subset? Add the default "regular" one
610
- if (! $hasTypes) {
611
- $wfConfigGoogleFamily .= ':regular';
612
- }
613
-
614
- $wfConfigGoogleFamily .= ':' . $subSetsStr;
615
  }
616
 
617
  // Append extra parameters to the last family from the list
47
  echo self::NOSCRIPT_WEB_FONT_LOADER;
48
  }, PHP_INT_MAX);
49
 
50
+ add_filter('wpacu_html_source_after_optimization', static function($htmlSource) {
51
+ // Is the mark still there and wasn't replaced? Strip it
52
+ return str_replace(FontsGoogle::NOSCRIPT_WEB_FONT_LOADER, '', $htmlSource);
53
+ });
54
+
55
  add_action('init', function() {
56
  // don't apply any changes if not in the front-end view (e.g. Dashboard view)
57
  // or test mode is enabled and a guest user is accessing the page
190
  continue;
191
  }
192
 
193
+ // Check if the CSS has any 'data-wpacu-skip' attribute; if it does, do not continue and leave it as it is (non-combined)
194
+ if (preg_match('#data-wpacu-skip([=>/ ])#i', $linkTag)) {
195
+ continue;
196
+ }
197
+
198
  preg_match_all('#href=(["\'])' . '(.*)' . '(["\'])#Usmi', $linkTag, $outputMatches);
199
  $linkHrefOriginal = $finalLinkHref = trim($outputMatches[2][0], '"\'');
200
 
239
  }
240
  }
241
 
242
+ $finalCombinableLinks = array_values($finalCombinableLinks);
243
+
244
  // Only proceed with the optimization/combine if there's obviously at least 2 combinable URL requests to Google Fonts
245
  // OR the loading type is different than render-blocking
246
  if (Main::instance()->settings['google_fonts_combine'] && (Main::instance()->settings['google_fonts_combine_type'] || count($finalCombinableLinks) > 1)) {
325
  foreach ($styleMatches as $styleInlineArray) {
326
  list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
327
 
328
+ // Check if the STYLE tag has any 'data-wpacu-skip' attribute; if it does, do not continue
329
+ if (preg_match('#data-wpacu-skip([=>/ ])#i', $styleInlineTag)) {
330
+ continue;
331
+ }
332
+
333
  // Is the content relevant?
334
  if (! preg_match('/@import(\s+|)(url|\(|\'|")/i', $styleInlineContent)
335
  || stripos($styleInlineContent, 'fonts.googleapis.com') === false) {
617
 
618
  // Any types? e.g. 400, 400italic, bold, etc.
619
  $hasTypes = false;
620
+ if (isset($fontValues['types']) && $fontValues['types']) {
621
+ $wfConfigGoogleFamily .= ':'.$fontValues['types'];
622
  $hasTypes = true;
623
  }
624
 
625
  if ($subSetsStr) {
626
+ // If there are types, continue to use the comma delimiter
627
+ $wfConfigGoogleFamily .= ($hasTypes ? ',' : ':') . $subSetsStr;
 
 
 
 
628
  }
629
 
630
  // Append extra parameters to the last family from the list
classes/OptimiseAssets/FontsGoogleRemove.php CHANGED
@@ -47,12 +47,8 @@ class FontsGoogleRemove
47
  */
48
  public static function cleanLinkTags($htmlSource)
49
  {
50
- // Cleaner HTML Source
51
- $altHtmlSource = preg_replace('@<(script|style)[^>]*?>.*?</\\1>@si', '', $htmlSource);
52
- $altHtmlSource = preg_replace('/<!--(.|\s)*?-->/', '', $altHtmlSource);
53
-
54
  // Do not continue if there is no single reference to the string we look for in the clean HTML source
55
- if (stripos($altHtmlSource, FontsGoogle::$containsStr) === false) {
56
  return $htmlSource;
57
  }
58
 
@@ -63,14 +59,28 @@ class FontsGoogleRemove
63
 
64
  $strContainsFormat = implode('|', $strContainsArray);
65
 
66
- preg_match_all('#<link[^>]*(' . $strContainsFormat . ').*(>)#Usmi', $altHtmlSource, $matchesFromLinkTags, PREG_SET_ORDER);
 
 
67
 
68
  // Needs to match at least one to carry on with the replacements
69
  if (isset($matchesFromLinkTags[0]) && ! empty($matchesFromLinkTags[0])) {
70
  foreach ($matchesFromLinkTags as $linkIndex => $linkTagArray) {
71
  $linkTag = trim(trim($linkTagArray[0], '"\''));
72
- $htmlSource = str_ireplace(array($linkTag."\n", $linkTag), '', $htmlSource);
 
 
 
 
 
 
 
 
 
 
73
  }
 
 
74
  }
75
 
76
  return $htmlSource;
@@ -97,6 +107,11 @@ class FontsGoogleRemove
97
  foreach ($styleMatches as $styleInlineArray) {
98
  list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
99
 
 
 
 
 
 
100
  $newStyleInlineTag = $styleInlineTag;
101
  $newStyleInlineContent = $styleInlineContent;
102
 
47
  */
48
  public static function cleanLinkTags($htmlSource)
49
  {
 
 
 
 
50
  // Do not continue if there is no single reference to the string we look for in the clean HTML source
51
+ if (stripos($htmlSource, FontsGoogle::$containsStr) === false) {
52
  return $htmlSource;
53
  }
54
 
59
 
60
  $strContainsFormat = implode('|', $strContainsArray);
61
 
62
+ preg_match_all('#<link[^>]*(' . $strContainsFormat . ').*(>)#Usmi', $htmlSource, $matchesFromLinkTags, PREG_SET_ORDER);
63
+
64
+ $stripLinksList = array();
65
 
66
  // Needs to match at least one to carry on with the replacements
67
  if (isset($matchesFromLinkTags[0]) && ! empty($matchesFromLinkTags[0])) {
68
  foreach ($matchesFromLinkTags as $linkIndex => $linkTagArray) {
69
  $linkTag = trim(trim($linkTagArray[0], '"\''));
70
+
71
+ if (strip_tags($linkTag) !== '') {
72
+ continue; // Something might be funny there, make sure the tag is valid
73
+ }
74
+
75
+ // Check if the Google Fonts CSS has any 'data-wpacu-skip' attribute; if it does, do not remove it
76
+ if (preg_match('#data-wpacu-skip([=>/ ])#i', $linkTag)) {
77
+ continue;
78
+ }
79
+
80
+ $stripLinksList[$linkTag] = '';
81
  }
82
+
83
+ $htmlSource = strtr($htmlSource, $stripLinksList);
84
  }
85
 
86
  return $htmlSource;
107
  foreach ($styleMatches as $styleInlineArray) {
108
  list($styleInlineTag, $styleInlineContent) = $styleInlineArray;
109
 
110
+ // Check if the STYLE tag has any 'data-wpacu-skip' attribute; if it does, do not continue
111
+ if (preg_match('#data-wpacu-skip([=>/ ])#i', $styleInlineTag)) {
112
+ continue;
113
+ }
114
+
115
  $newStyleInlineTag = $styleInlineTag;
116
  $newStyleInlineContent = $styleInlineContent;
117
 
classes/OptimiseAssets/MinifyCss.php CHANGED
@@ -21,6 +21,17 @@ class MinifyCss
21
  public static function applyMinification($cssContent, $forInlineStyle = false)
22
  {
23
  if (class_exists('\MatthiasMullie\Minify\CSS')) {
 
 
 
 
 
 
 
 
 
 
 
24
  $minifier = new \MatthiasMullie\Minify\CSS( $cssContent );
25
 
26
  if ( $forInlineStyle ) {
@@ -29,7 +40,18 @@ class MinifyCss
29
  $minifier->setImportExtensions( array() );
30
  }
31
 
32
- return trim( $minifier->minify() );
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  return $cssContent;
@@ -111,61 +133,127 @@ class MinifyCss
111
  return $htmlSource; // no STYLE tags
112
  }
113
 
114
- // DOMDocument extension has to be enabled, otherwise return the HTML source as was (no changes)
115
- if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument'))) {
116
- return $htmlSource;
117
- }
118
-
119
- $domTag = new \DOMDocument();
120
- libxml_use_internal_errors(true);
121
- $domTag->loadHTML($htmlSource);
122
-
123
- $styleTagsObj = $domTag->getElementsByTagName( 'style' );
124
-
125
- if ($styleTagsObj === null) {
126
- return $htmlSource;
127
- }
128
-
129
  $skipTagsContaining = array(
 
130
  'astra-theme-css-inline-css',
131
  'astra-edd-inline-css',
132
  'et-builder-module-design-cached-inline-styles',
133
  'fusion-stylesheet-inline-css',
134
  'woocommerce-general-inline-css',
135
  'woocommerce-inline-inline-css',
136
- 'data-wpacu-own-inline-style', // Only shown to the admin, irrelevant for any optimization (save resources)
137
- 'data-wpacu-inline-css-file' // already minified/optimized since the INLINE was generated from the cached file
 
 
138
  );
139
 
140
- foreach ($styleTagsObj as $styleTagObj) {
141
- $originalTag = CleanUp::getOuterHTML($styleTagObj);
142
 
143
- // No need to use extra resources as the tag is already minified
144
- if (preg_match('('.implode('|', $skipTagsContaining).')', $originalTag)) {
145
- continue;
 
146
  }
147
 
148
- $originalTagContents = (isset($styleTagObj->nodeValue) && trim($styleTagObj->nodeValue) !== '') ? $styleTagObj->nodeValue : false;
149
 
150
- if ($originalTagContents) {
151
- $newTagContents = OptimizeCss::maybeAlterCssContent($originalTagContents, true, true, array('just_minify'));
152
 
153
- // Only comments or no content added to the inline STYLE tag? Strip it completely to reduce the number of DOM elements
154
- if ($newTagContents === '/**/' || ! $newTagContents) {
155
- $htmlSource = str_ireplace('>'.$originalTagContents.'</style', '></style', $htmlSource);
156
 
157
- preg_match_all('#<style.*?>#si', $originalTag, $matchesFromStyle);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- if (isset($matchesFromStyle[0][0]) && $styleTagWithoutContent = $matchesFromStyle[0][0]) {
160
- $styleTagWithoutContentAlt = str_replace('"', '\'', $styleTagWithoutContent);
161
- $htmlSource = str_ireplace(array($styleTagWithoutContent.'</style>', $styleTagWithoutContentAlt.'</style>'), '', $htmlSource);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
- } else {
164
- // It has content; do the replacement
165
- $htmlSource = str_ireplace( '>' . $originalTagContents . '</style',
166
- '>' . $newTagContents . '</style', $htmlSource );
167
  }
168
- libxml_clear_errors();
169
  }
170
  }
171
 
21
  public static function applyMinification($cssContent, $forInlineStyle = false)
22
  {
23
  if (class_exists('\MatthiasMullie\Minify\CSS')) {
24
+ $sha1OriginalContent = sha1($cssContent);
25
+
26
+ // Let's check if the content is already minified
27
+ // Save resources as the minify process can take time if the content is very large
28
+ if (OptimizeCommon::originalContentIsAlreadyMarkedAsMinified($sha1OriginalContent, 'styles')) {
29
+ return $cssContent;
30
+ }
31
+
32
+ // Minify it
33
+ $alreadyMinified = false; // default
34
+
35
  $minifier = new \MatthiasMullie\Minify\CSS( $cssContent );
36
 
37
  if ( $forInlineStyle ) {
40
  $minifier->setImportExtensions( array() );
41
  }
42
 
43
+ $minifiedContent = trim( $minifier->minify() );
44
+
45
+ if ($minifiedContent === $cssContent) {
46
+ $alreadyMinified = true;
47
+ }
48
+
49
+ // If the resulting content is the same, mark it as minified to avoid the minify process next time
50
+ if ($alreadyMinified) {
51
+ OptimizeCommon::originalContentMarkAsAlreadyMinified( $sha1OriginalContent, 'styles' );
52
+ }
53
+
54
+ return $minifiedContent;
55
  }
56
 
57
  return $cssContent;
133
  return $htmlSource; // no STYLE tags
134
  }
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  $skipTagsContaining = array(
137
+ 'data-wpacu-skip',
138
  'astra-theme-css-inline-css',
139
  'astra-edd-inline-css',
140
  'et-builder-module-design-cached-inline-styles',
141
  'fusion-stylesheet-inline-css',
142
  'woocommerce-general-inline-css',
143
  'woocommerce-inline-inline-css',
144
+ 'data-wpacu-own-inline-style',
145
+ // Only shown to the admin, irrelevant for any optimization (save resources)
146
+ 'data-wpacu-inline-css-file'
147
+ // already minified/optimized since the INLINE was generated from the cached file
148
  );
149
 
150
+ $fetchType = 'regex';
 
151
 
152
+ if ($fetchType === 'dom') {
153
+ // DOMDocument extension has to be enabled, otherwise return the HTML source as was (no changes)
154
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument'))) {
155
+ return $htmlSource;
156
  }
157
 
158
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'minifyInlineStyleTags');
159
 
160
+ $styleTagsObj = $domTag->getElementsByTagName( 'style' );
 
161
 
162
+ if ( $styleTagsObj === null ) {
163
+ return $htmlSource;
164
+ }
165
 
166
+ foreach ( $styleTagsObj as $styleTagObj ) {
167
+ $originalTag = CleanUp::getOuterHTML( $styleTagObj );
168
+
169
+ // No need to use extra resources as the tag is already minified
170
+ if ( preg_match( '(' . implode( '|', $skipTagsContaining ) . ')', $originalTag ) ) {
171
+ continue;
172
+ }
173
+
174
+ $originalTagContents = ( isset( $styleTagObj->nodeValue ) && trim( $styleTagObj->nodeValue ) !== '' ) ? $styleTagObj->nodeValue : false;
175
+
176
+ if ( $originalTagContents ) {
177
+ $newTagContents = OptimizeCss::maybeAlterContentForInlineStyleTag( $originalTagContents, true, array( 'just_minify' ) );
178
+
179
+ // Only comments or no content added to the inline STYLE tag? Strip it completely to reduce the number of DOM elements
180
+ if ( $newTagContents === '/**/' || ! $newTagContents ) {
181
+ $htmlSource = str_ireplace( '>' . $originalTagContents . '</style', '></style', $htmlSource );
182
+
183
+ preg_match( '#<style.*?>#si', $originalTag, $matchFromStyle );
184
+
185
+ if ( isset( $matchFromStyle[0] ) && $styleTagWithoutContent = $matchFromStyle[0] ) {
186
+ $styleTagWithoutContentAlt = str_replace( '"', '\'', $styleTagWithoutContent );
187
+ $htmlSource = str_ireplace( array(
188
+ $styleTagWithoutContent . '</style>',
189
+ $styleTagWithoutContentAlt . '</style>'
190
+ ), '', $htmlSource );
191
+ }
192
+ } else {
193
+ // It has content; do the replacement
194
+ $htmlSource = str_ireplace(
195
+ '>' . $originalTagContents . '</style>',
196
+ '>' . $newTagContents . '</style>',
197
+ $htmlSource
198
+ );
199
+ }
200
+ libxml_clear_errors();
201
+ }
202
+ }
203
+ } elseif ($fetchType === 'regex') {
204
+ preg_match_all( '@(<style[^>]*?>).*?</style>@si', $htmlSource, $matchesStyleTags, PREG_SET_ORDER );
205
+
206
+ if ( $matchesStyleTags === null ) {
207
+ return $htmlSource;
208
+ }
209
+
210
+ foreach ($matchesStyleTags as $matchedStyle) {
211
+ if ( ! (isset($matchedStyle[0]) && $matchedStyle[0]) ) {
212
+ continue;
213
+ }
214
+
215
+ $originalTag = $matchedStyle[0];
216
+
217
+ if (substr($originalTag, -strlen('></style>')) === strtolower('></style>')) {
218
+ // No empty STYLE tags
219
+ continue;
220
+ }
221
+
222
+ // No need to use extra resources as the tag is already minified
223
+ if ( preg_match( '(' . implode( '|', $skipTagsContaining ) . ')', $originalTag ) ) {
224
+ continue;
225
+ }
226
 
227
+ $tagOpen = $matchedStyle[1];
228
+
229
+ $withTagOpenStripped = substr($originalTag, strlen($tagOpen));
230
+ $originalTagContents = substr($withTagOpenStripped, 0, -strlen('</style>'));
231
+
232
+ if ( $originalTagContents ) {
233
+ $newTagContents = OptimizeCss::maybeAlterContentForInlineStyleTag( $originalTagContents, true, array( 'just_minify' ) );
234
+
235
+ // Only comments or no content added to the inline STYLE tag? Strip it completely to reduce the number of DOM elements
236
+ if ( $newTagContents === '/**/' || ! $newTagContents ) {
237
+ $htmlSource = str_replace( '>' . $originalTagContents . '</', '></', $htmlSource );
238
+
239
+ preg_match( '#<style.*?>#si', $originalTag, $matchFromStyle );
240
+
241
+ if ( isset( $matchFromStyle[0] ) && $styleTagWithoutContent = $matchFromStyle[0] ) {
242
+ $styleTagWithoutContentAlt = str_ireplace( '"', '\'', $styleTagWithoutContent );
243
+ $htmlSource = str_ireplace( array(
244
+ $styleTagWithoutContent . '</style>',
245
+ $styleTagWithoutContentAlt . '</style>'
246
+ ), '', $htmlSource );
247
+ }
248
+ } else {
249
+ // It has content; do the replacement
250
+ $htmlSource = str_replace(
251
+ '>' . $originalTagContents . '</style>',
252
+ '>' . $newTagContents . '</style>',
253
+ $htmlSource
254
+ );
255
  }
 
 
 
 
256
  }
 
257
  }
258
  }
259
 
classes/OptimiseAssets/MinifyJs.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  namespace WpAssetCleanUp\OptimiseAssets;
3
 
 
4
  use WpAssetCleanUp\Main;
5
  use WpAssetCleanUp\Menu;
6
  use WpAssetCleanUp\MetaBoxes;
@@ -19,8 +20,31 @@ class MinifyJs
19
  public static function applyMinification($jsContent)
20
  {
21
  if (class_exists('\MatthiasMullie\Minify\JS')) {
 
 
 
 
 
 
 
 
 
 
 
22
  $minifier = new \MatthiasMullie\Minify\JS($jsContent);
23
- return trim($minifier->minify());
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
  return $jsContent;
@@ -88,6 +112,128 @@ class MinifyJs
88
  return false;
89
  }
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  /**
92
  * @return bool
93
  */
1
  <?php
2
  namespace WpAssetCleanUp\OptimiseAssets;
3
 
4
+ use WpAssetCleanUp\CleanUp;
5
  use WpAssetCleanUp\Main;
6
  use WpAssetCleanUp\Menu;
7
  use WpAssetCleanUp\MetaBoxes;
20
  public static function applyMinification($jsContent)
21
  {
22
  if (class_exists('\MatthiasMullie\Minify\JS')) {
23
+ $sha1OriginalContent = sha1($jsContent);
24
+
25
+ // Let's check if the content is already minified
26
+ // Save resources as the minify process can take time if the content is very large
27
+ if (OptimizeCommon::originalContentIsAlreadyMarkedAsMinified($sha1OriginalContent, 'scripts')) {
28
+ return $jsContent; // return the already minified content, saving resources
29
+ }
30
+
31
+ // Minify it
32
+ $alreadyMinified = false; // default
33
+
34
  $minifier = new \MatthiasMullie\Minify\JS($jsContent);
35
+ $minifiedContent = trim($minifier->minify());
36
+
37
+ if (trim($minifiedContent) === trim(trim($jsContent, ';'))) {
38
+ $minifiedContent = $jsContent; // consider them the same if only the ; at the end was stripped (it doesn't worth the resources that would be used)
39
+ $alreadyMinified = true;
40
+ }
41
+
42
+ // If the resulting content is the same, mark it as minified to avoid the minify process next time
43
+ if ($alreadyMinified) {
44
+ OptimizeCommon::originalContentMarkAsAlreadyMinified($sha1OriginalContent, 'scripts');
45
+ }
46
+
47
+ return $minifiedContent;
48
  }
49
 
50
  return $jsContent;
112
  return false;
113
  }
114
 
115
+ /**
116
+ * @param $htmlSource
117
+ *
118
+ * @return mixed|string
119
+ */
120
+ public static function minifyInlineScriptTags($htmlSource)
121
+ {
122
+ if (stripos($htmlSource, '<script') === false) {
123
+ return $htmlSource; // no SCRIPT tags, hmm
124
+ }
125
+
126
+ $skipTagsContaining = array_map( static function ( $toMatch ) {
127
+ return preg_quote($toMatch, '/');
128
+ }, array(
129
+ 'data-wpacu-skip',
130
+ '/* <![CDATA[ */', // added via wp_localize_script()
131
+ 'wpacu-google-fonts-async-load',
132
+ 'wpacu-preload-async-css-fallback',
133
+ /* [wpacu_pro] */'data-wpacu-inline-js-file',/* [/wpacu_pro] */
134
+ 'document.body.prepend(wpacuLinkTag',
135
+ 'var wc_product_block_data = JSON.parse( decodeURIComponent(',
136
+ '/(^|\s)(no-)?customize-support(?=\s|$)/', // WP Core
137
+ 'b[c] += ( window.postMessage && request ? \' \' : \' no-\' ) + cs;', // WP Core
138
+ 'data-wpacu-own-inline-script', // Only shown to the admin, irrelevant for any optimization (save resources)
139
+ // [wpacu_pro]
140
+ 'data-wpacu-inline-js-file', // already minified/optimized since the INLINE was generated from the cached file
141
+ // [/wpacu_pro]
142
+ ));
143
+
144
+ // Do not perform another \DOMDocument call if it was done already somewhere else (e.g. CombineJs)
145
+ $fetchType = 'regex'; // 'regex' or 'dom'
146
+
147
+ if ( $fetchType === 'dom' ) {
148
+ // DOMDocument extension has to be enabled, otherwise return the HTML source as was (no changes)
149
+ if ( ! ( function_exists( 'libxml_use_internal_errors' ) && function_exists( 'libxml_clear_errors' ) && class_exists( '\DOMDocument' ) ) ) {
150
+ return $htmlSource;
151
+ }
152
+
153
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'minifyInlineScriptTags');
154
+
155
+ $scriptTagsObj = $domTag->getElementsByTagName( 'script' );
156
+
157
+ if ( $scriptTagsObj === null ) {
158
+ return $htmlSource;
159
+ }
160
+
161
+ foreach ( $scriptTagsObj as $scriptTagObj ) {
162
+ // Does it have the "src" attribute? Skip it as it's not an inline SCRIPT tag
163
+ if ( isset( $scriptTagObj->attributes ) && $scriptTagObj->attributes !== null ) {
164
+ foreach ( $scriptTagObj->attributes as $attrObj ) {
165
+ if ( $attrObj->nodeName === 'src' ) {
166
+ continue 2;
167
+ }
168
+
169
+ if ( $attrObj->nodeName === 'type' && $attrObj->nodeValue !== 'text/javascript' ) {
170
+ // If a "type" parameter exists (otherwise it defaults to "text/javascript"
171
+ // and the value of "type" is not "text/javascript", do not proceed with any optimization (including minification)
172
+ continue 2;
173
+ }
174
+ }
175
+ }
176
+
177
+ $originalTag = CleanUp::getOuterHTML( $scriptTagObj );
178
+
179
+ // No need to use extra resources as the tag is already minified
180
+ if ( preg_match( '/(' . implode( '|', $skipTagsContaining ) . ')/', $originalTag ) ) {
181
+ continue;
182
+ }
183
+
184
+ $originalTagContents = ( isset( $scriptTagObj->nodeValue ) && trim( $scriptTagObj->nodeValue ) !== '' ) ? $scriptTagObj->nodeValue : false;
185
+
186
+ if ( $originalTagContents ) {
187
+ $newTagContents = OptimizeJs::maybeAlterContentForInlineScriptTag( $originalTagContents, true );
188
+
189
+ if ( $newTagContents !== $originalTagContents ) {
190
+ $htmlSource = str_ireplace(
191
+ '>' . $originalTagContents . '</script',
192
+ '>' . $newTagContents . '</script',
193
+ $htmlSource
194
+ );
195
+ }
196
+
197
+ libxml_clear_errors();
198
+ }
199
+ }
200
+ } elseif ($fetchType === 'regex') {
201
+ preg_match_all( '@(<script[^>]*?>).*?</script>@si', $htmlSource, $matchesScriptTags, PREG_SET_ORDER );
202
+
203
+ if ( $matchesScriptTags === null ) {
204
+ return $htmlSource;
205
+ }
206
+
207
+ foreach ($matchesScriptTags as $matchedScript) {
208
+ if (isset($matchedScript[0]) && $matchedScript[0]) {
209
+ $originalTag = $matchedScript[0];
210
+
211
+ if (strpos($originalTag, 'src=') && strtolower(substr($originalTag, -strlen('></script>'))) === strtolower('></script>')) {
212
+ // Only inline SCRIPT tags allowed
213
+ continue;
214
+ }
215
+
216
+ // No need to use extra resources as the tag is already minified
217
+ if ( preg_match( '/(' . implode( '|', $skipTagsContaining ) . ')/', $originalTag ) ) {
218
+ continue;
219
+ }
220
+
221
+ $tagOpen = $matchedScript[1];
222
+ $withTagOpenStripped = substr($originalTag, strlen($tagOpen));
223
+ $originalTagContents = substr($withTagOpenStripped, 0, -strlen('</script>'));
224
+
225
+ $newTagContents = OptimizeJs::maybeAlterContentForInlineScriptTag( $originalTagContents, true );
226
+
227
+ if ( $newTagContents !== $originalTagContents ) {
228
+ $htmlSource = str_ireplace( '>' . $originalTagContents . '</script', '>' . $newTagContents . '</script', $htmlSource );
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ return $htmlSource;
235
+ }
236
+
237
  /**
238
  * @return bool
239
  */
classes/OptimiseAssets/OptimizeCommon.php CHANGED
@@ -7,7 +7,9 @@ use WpAssetCleanUp\HardcodedAssets;
7
  use WpAssetCleanUp\Main;
8
  use WpAssetCleanUp\Menu;
9
  use WpAssetCleanUp\Misc;
 
10
  use WpAssetCleanUp\Plugin;
 
11
  use WpAssetCleanUp\Settings;
12
  use WpAssetCleanUp\Tools;
13
 
@@ -47,20 +49,20 @@ class OptimizeCommon
47
  */
48
  public function init()
49
  {
50
- add_action('switch_theme', array($this, 'clearAllCache'));
51
- add_action('after_switch_theme', array($this, 'clearAllCache'));
52
 
53
  // Is WP Rocket's page cache cleared? Clear Asset CleanUp's CSS cache files too
54
  if (array_key_exists('action', $_GET) && $_GET['action'] === 'purge_cache') {
55
  // Leave its default parameters, no redirect needed
56
  add_action('init', static function() {
57
- OptimizeCommon::clearAllCache();
58
  }, PHP_INT_MAX);
59
  }
60
 
61
  add_action('admin_post_assetcleanup_clear_assets_cache', static function() {
62
  set_transient('wpacu_clear_assets_cache_via_link', true);
63
- self::clearAllCache(true);
64
  });
65
 
66
  // When a post is moved to the trash / deleted
@@ -155,18 +157,21 @@ class OptimizeCommon
155
  return $htmlSource;
156
  }
157
 
 
 
 
 
 
 
158
  // This is useful to avoid changing the DOM via wp_loaded action hook
159
  // In order to check how fast the page loads without the DOM changes (for debugging purposes)
160
  $wpacuNoHtmlChanges = array_key_exists( 'wpacu_no_html_changes', $_GET );
161
 
162
  if ( $wpacuNoHtmlChanges || Plugin::preventAnyChanges() ) {
 
163
  return $htmlSource;
164
  }
165
 
166
- // [wpacu_timing]
167
- Misc::scriptExecTimer( 'alter_html_source' );
168
- // [/wpacu_timing]
169
-
170
  $htmlSource = apply_filters( 'wpacu_html_source_before_optimization', $htmlSource );
171
 
172
  // For the admin
@@ -174,14 +179,26 @@ class OptimizeCommon
174
 
175
  // The admin is editing the CSS/JS list within the front-end view
176
  if (HardcodedAssets::useBufferingForEditFrontEndView()) {
177
- wp_cache_set('wpacu_hardcoded_assets_encoded', base64_encode( json_encode($anyHardCodedAssetsList) ));
178
  }
179
 
180
  $htmlSource = OptimizeCss::alterHtmlSource( $htmlSource );
181
  $htmlSource = OptimizeJs::alterHtmlSource( $htmlSource );
182
 
 
 
 
 
 
 
 
183
  $htmlSource = Main::instance()->settings['remove_generator_tag'] ? CleanUp::removeMetaGenerators( $htmlSource ) : $htmlSource;
184
- $htmlSource = Main::instance()->settings['remove_html_comments'] ? CleanUp::removeHtmlComments( $htmlSource ) : $htmlSource;
 
 
 
 
 
185
 
186
  if ( in_array( Main::instance()->settings['disable_xmlrpc'], array( 'disable_all', 'disable_pingback' ) ) ) {
187
  // Also clean it up from the <head> in case it's hardcoded
@@ -190,16 +207,22 @@ class OptimizeCommon
190
 
191
  $htmlSource = apply_filters( 'wpacu_html_source', $htmlSource ); // legacy
192
 
193
- // [wpacu_timing]
194
- Misc::scriptExecTimer( 'alter_html_source', 'end' );
195
- // [/wpacu_timing]
196
 
197
  // [wpacu_debug]
198
  if (array_key_exists('wpacu_debug', $_GET)) {
199
  $timingKeys = array(
 
 
 
200
  // All HTML alteration via "wp_loaded" action hook
201
  'alter_html_source',
202
 
 
 
 
 
 
203
  // CSS
204
  'alter_html_source_for_optimize_css',
205
  'alter_html_source_unload_ignore_deps_css',
@@ -219,7 +242,13 @@ class OptimizeCommon
219
  'alter_html_source_for_preload_js',
220
  'alter_html_source_for_combine_js',
221
 
222
- 'alter_html_source_move_inline_jquery_after_src_tag'
 
 
 
 
 
 
223
  );
224
 
225
  foreach ( $timingKeys as $timingKey ) {
@@ -231,6 +260,80 @@ class OptimizeCommon
231
  return apply_filters( 'wpacu_html_source_after_optimization', $htmlSource );
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  /**
235
  * @return string
236
  */
@@ -245,64 +348,37 @@ class OptimizeCommon
245
  }
246
 
247
  /**
248
- * Removes HTML comments
249
- * and not combined with other JavaScript files in case the method is called from CombineJs.php
250
- *
251
- * The following output is used only for fetching purposes
252
  * It will not be part of the final output
253
  *
254
- * @param $htmlSource
255
  * @param $params
256
  *
257
  * @return string|string[]|null
258
  */
259
- public static function cleanerHtmlSource($htmlSource, $params = array())
260
  {
261
- $htmlSourceBeforeAlt = $htmlSource;
 
 
 
 
 
262
 
263
  // Case: Return the HTML source without any conditional comments and the content within them
264
  if (in_array('strip_content_between_conditional_comments', $params)) {
265
- preg_match_all('#<!--\[if(.*?)]>(<!-->|-->|\s|)(.*?)(<!--<!|<!)\[endif]-->#si', $htmlSource, $matchedContent);
266
 
267
  if (isset($matchedContent[0]) && ! empty($matchedContent[0])) {
268
  foreach ($matchedContent[0] as $conditionalHtmlContent) {
269
- $htmlSourceBeforeAlt = str_replace($conditionalHtmlContent, '', $htmlSourceBeforeAlt);
270
  }
271
- return $htmlSourceBeforeAlt;
272
- }
273
- }
274
-
275
- $sourceHasComments = strpos($htmlSource, '<!--') !== false && strpos($htmlSource, '-->') !== false;
276
-
277
- if (! $sourceHasComments) {
278
- return $htmlSource; // nothing to clean
279
- }
280
-
281
- if (function_exists('libxml_use_internal_errors') && class_exists('\DOMDocument') && class_exists('\DOMXPath')) {
282
- // Highest accuracy
283
- $dom = new \DOMDocument();
284
- libxml_use_internal_errors(true);
285
- $dom->loadHtml($htmlSource);
286
 
287
- $xpath = new \DOMXPath($dom);
288
- libxml_use_internal_errors(true);
289
- foreach ($xpath->query('//comment()') as $comment) {
290
- if (isset($comment->nodeValue) && $comment->nodeValue) {
291
- $htmlSource = str_replace( '<!--' . $comment->nodeValue . '-->', '', $htmlSource );
292
- }
293
  }
294
-
295
- return $htmlSource; // altered via DOMDocument
296
  }
297
 
298
- // Fallback (RegEx)
299
- $htmlSource = trim(preg_replace('/<!--(.|\s)*?-->/', '', $htmlSource));
300
-
301
- if (! $htmlSource) {
302
- return $htmlSourceBeforeAlt; // It returned null (rare cases with some pages, possible bug, return the source as it is)
303
- }
304
-
305
- return $htmlSource; // altered via RegEx (fallback)
306
  }
307
 
308
  /**
@@ -844,9 +920,9 @@ class OptimizeCommon
844
  *
845
  * @param bool $redirectAfter
846
  */
847
- public static function clearAllCache($redirectAfter = false)
848
  {
849
- if (self::doNotClearAllCache()) {
850
  return;
851
  }
852
 
@@ -1027,6 +1103,38 @@ SQL;
1027
  @rmdir(WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir().'one');
1028
  @rmdir(WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir().'one');
1029
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1030
  /*
1031
  * STEP 2: Remove all transients related to the Minify CSS/JS files feature
1032
  */
@@ -1058,6 +1166,16 @@ SQL;
1058
  }
1059
  }
1060
 
 
 
 
 
 
 
 
 
 
 
1061
  /**
1062
  * This is usually done when the plugin is deactivated
1063
  * e.g. if you use Autoptimize and it remains active, you will likely want to have its caching cleared with traces from Asset CleanUp
@@ -1121,7 +1239,7 @@ SQL;
1121
  *
1122
  * @return bool
1123
  */
1124
- public static function doNotClearAllCache()
1125
  {
1126
  // WooCommerce GET or AJAX call
1127
  if (array_key_exists('wc-ajax', $_GET) && $_GET['wc-ajax']) {
@@ -1197,7 +1315,7 @@ SQL;
1197
  */
1198
  public static function stripSourceMap($assetContent)
1199
  {
1200
- return str_replace('# sourceMappingURL=', '# From Source Map: ', $assetContent);
1201
  }
1202
 
1203
  /**
@@ -1213,7 +1331,7 @@ SQL;
1213
 
1214
  $ignoreQueryStrings = array(
1215
  'wpacu_do_combine', // show the CSS/JS as combined IF the option is enabled despite the query string (for debugging purposes)
1216
- 'wpacu_no_css_minify', 'wpacu_no_js_minify', 'wpacu_no_css_combine', 'wpacu_no_js_combine', 'wpacu_debug', 'wpacu_skip_test_mode',
1217
  'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_expid', 'utm_referrer', // Google Analytics
1218
  'gclid', // Google Click ID
1219
  'fbclick', 'fbclid', 'fb_action_ids', 'fb_action_types', 'fb_source', // Facebook
@@ -1437,4 +1555,49 @@ SQL;
1437
  @rmdir($targetDir);
1438
  }
1439
  }
1440
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  use WpAssetCleanUp\Main;
8
  use WpAssetCleanUp\Menu;
9
  use WpAssetCleanUp\Misc;
10
+ use WpAssetCleanUp\ObjectCache;
11
  use WpAssetCleanUp\Plugin;
12
+ use WpAssetCleanUp\Preloads;
13
  use WpAssetCleanUp\Settings;
14
  use WpAssetCleanUp\Tools;
15
 
49
  */
50
  public function init()
51
  {
52
+ add_action('switch_theme', array($this, 'clearCache' ));
53
+ add_action('after_switch_theme', array($this, 'clearCache' ));
54
 
55
  // Is WP Rocket's page cache cleared? Clear Asset CleanUp's CSS cache files too
56
  if (array_key_exists('action', $_GET) && $_GET['action'] === 'purge_cache') {
57
  // Leave its default parameters, no redirect needed
58
  add_action('init', static function() {
59
+ OptimizeCommon::clearCache();
60
  }, PHP_INT_MAX);
61
  }
62
 
63
  add_action('admin_post_assetcleanup_clear_assets_cache', static function() {
64
  set_transient('wpacu_clear_assets_cache_via_link', true);
65
+ self::clearCache(true);
66
  });
67
 
68
  // When a post is moved to the trash / deleted
157
  return $htmlSource;
158
  }
159
 
160
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source' ); /* [/wpacu_timing] */
161
+
162
+ // Front-end View
163
+ // The printing of the hardcoded assets is made via "wpacu_final_frontend_output" filter hook
164
+ // located within "shutdown" action hook only if the user is logged-in and has the right permissions
165
+
166
  // This is useful to avoid changing the DOM via wp_loaded action hook
167
  // In order to check how fast the page loads without the DOM changes (for debugging purposes)
168
  $wpacuNoHtmlChanges = array_key_exists( 'wpacu_no_html_changes', $_GET );
169
 
170
  if ( $wpacuNoHtmlChanges || Plugin::preventAnyChanges() ) {
171
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source', 'end' ); /* [/wpacu_timing] */
172
  return $htmlSource;
173
  }
174
 
 
 
 
 
175
  $htmlSource = apply_filters( 'wpacu_html_source_before_optimization', $htmlSource );
176
 
177
  // For the admin
179
 
180
  // The admin is editing the CSS/JS list within the front-end view
181
  if (HardcodedAssets::useBufferingForEditFrontEndView()) {
182
+ ObjectCache::wpacu_cache_set('wpacu_hardcoded_assets_encoded', base64_encode( json_encode($anyHardCodedAssetsList) ));
183
  }
184
 
185
  $htmlSource = OptimizeCss::alterHtmlSource( $htmlSource );
186
  $htmlSource = OptimizeJs::alterHtmlSource( $htmlSource );
187
 
188
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source_cleanup' ); /* [/wpacu_timing] */
189
+
190
+ /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_remove_html_comments'); /* [/wpacu_timing] */
191
+ $htmlSource = Main::instance()->settings['remove_html_comments'] ? CleanUp::removeHtmlComments( $htmlSource, false, 'final_output' ) : $htmlSource;
192
+ /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_remove_html_comments', 'end'); /* [/wpacu_timing] */
193
+
194
+ /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_remove_meta_generators'); /* [/wpacu_timing] */
195
  $htmlSource = Main::instance()->settings['remove_generator_tag'] ? CleanUp::removeMetaGenerators( $htmlSource ) : $htmlSource;
196
+ /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_remove_meta_generators', 'end'); /* [/wpacu_timing] */
197
+
198
+ $htmlSource = preg_replace('#<link(.*)data-wpacu-style-handle=\'(.*)\'#Umi', '<link \\1', $htmlSource);
199
+ $htmlSource = str_replace(Preloads::DEL_STYLES_PRELOADS, '', $htmlSource);
200
+
201
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source_cleanup', 'end' ); /* [/wpacu_timing] */
202
 
203
  if ( in_array( Main::instance()->settings['disable_xmlrpc'], array( 'disable_all', 'disable_pingback' ) ) ) {
204
  // Also clean it up from the <head> in case it's hardcoded
207
 
208
  $htmlSource = apply_filters( 'wpacu_html_source', $htmlSource ); // legacy
209
 
210
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'alter_html_source', 'end' ); /* [/wpacu_timing] */
 
 
211
 
212
  // [wpacu_debug]
213
  if (array_key_exists('wpacu_debug', $_GET)) {
214
  $timingKeys = array(
215
+ 'prepare_optimize_files_css',
216
+ 'prepare_optimize_files_js',
217
+
218
  // All HTML alteration via "wp_loaded" action hook
219
  'alter_html_source',
220
 
221
+ // HTML CleanUp
222
+ 'alter_html_source_cleanup',
223
+ 'alter_html_source_for_remove_html_comments',
224
+ 'alter_html_source_for_remove_meta_generators',
225
+
226
  // CSS
227
  'alter_html_source_for_optimize_css',
228
  'alter_html_source_unload_ignore_deps_css',
242
  'alter_html_source_for_preload_js',
243
  'alter_html_source_for_combine_js',
244
 
245
+ 'fetch_strip_hardcoded_assets',
246
+ 'fetch_all_hardcoded_assets',
247
+
248
+ 'output_css_js_manager',
249
+
250
+ 'style_loader_tag',
251
+ 'script_loader_tag'
252
  );
253
 
254
  foreach ( $timingKeys as $timingKey ) {
260
  return apply_filters( 'wpacu_html_source_after_optimization', $htmlSource );
261
  }
262
 
263
+ /**
264
+ * @param $htmlSource
265
+ * @param $for
266
+ *
267
+ * @return bool|\DOMDocument|mixed
268
+ */
269
+ public static function getDomLoadedTag($htmlSource, $for = '')
270
+ {
271
+ $htmlSourceBefore = $htmlSource;
272
+
273
+ $domTag = new \DOMDocument();
274
+ libxml_use_internal_errors( true );
275
+
276
+ $cleanerDomRegEx = '';
277
+
278
+ // [HTML CleanUp]
279
+ if ($for === 'removeHtmlComments') {
280
+ // Strip them to get a cleaner DOM that will be fetched for something else
281
+ $cleanerDomRegEx = '';
282
+ }
283
+
284
+ if ($for === 'removeHtmlCommentsFinal') {
285
+ $cleanerDomRegEx = array('@<(script|style)[^>]*?>.*?</\\1>@si', '#<(meta|link|img)([^<>]+)/?>#iU');
286
+ }
287
+
288
+ if ($for === 'removeMetaGenerators') {
289
+ $cleanerDomRegEx = array('@<(noscript|style|script)[^>]*?>.*?</\\1>@si', '#<(link|img)([^<>]+)/?>#iU');
290
+ }
291
+ // [/HTML CleanUp]
292
+
293
+ // [CSS Optimisation]
294
+ if ($for === 'combineCss') {
295
+ $cleanerDomRegEx = array('@<(noscript|style|script)[^>]*?>.*?</\\1>@si', '#<(meta|img)([^<>]+)/?>#iU');
296
+ }
297
+
298
+ if ($for === 'minifyInlineStyleTags') {
299
+ $cleanerDomRegEx = array('@<(noscript|script)[^>]*?>.*?</\\1>@si', '#<(meta|link|img)([^<>]+)/?>#iU');
300
+ }
301
+ // [/CSS Optimisation]
302
+
303
+ // [JS Optimisation]
304
+ if ($for === 'moveInlinejQueryAfterjQuerySrc') {
305
+ $cleanerDomRegEx = '@<(noscript|style)[^>]*?>.*?</\\1>@si';
306
+ }
307
+
308
+ if ($for === 'minifyInlineScriptTags') {
309
+ $cleanerDomRegEx = array('@<(noscript|style)[^>]*?>.*?</\\1>@si', '#<(meta|link|img)([^<>]+)/?>#iU');
310
+ }
311
+
312
+ if ($for === 'combineJs') {
313
+ $cleanerDomRegEx = '@<(noscript|style)[^>]*?>.*?</\\1>@si';
314
+ }
315
+ // [/JS Optimisation]
316
+
317
+ // Default: Strip just the NOSCRIPT tags
318
+ if ($cleanerDomRegEx !== '') {
319
+ $htmlSource = preg_replace( $cleanerDomRegEx, '', $htmlSource );
320
+ }
321
+
322
+ if (Main::instance()->isFrontendEditView) {
323
+ $htmlSource = preg_replace( '@<form action="#wpacu_wrap_assets" method="post">.*?</form>@si', '', $htmlSource );
324
+ }
325
+
326
+ // Avoid "Warning: DOMDocument::loadHTML(): Empty string supplied as input"
327
+ // Just in case $htmlSource has been altered incorrectly for any reason, fallback to the original $htmlSource value ($htmlSourceBefore)
328
+ if (! $htmlSource) {
329
+ $domTag->loadHTML($htmlSourceBefore);
330
+ return $domTag;
331
+ }
332
+
333
+ $domTag->loadHTML($htmlSource);
334
+ return $domTag;
335
+ }
336
+
337
  /**
338
  * @return string
339
  */
348
  }
349
 
350
  /**
351
+ * The following output is ONLY used for fetching purposes
 
 
 
352
  * It will not be part of the final output
353
  *
354
+ * @param $htmlSourceToFetchFrom
355
  * @param $params
356
  *
357
  * @return string|string[]|null
358
  */
359
+ public static function cleanerHtmlSource($htmlSourceToFetchFrom, $params = array('strip_content_between_conditional_comments'))
360
  {
361
+ if (in_array('for_fetching_link_tags', $params)) {
362
+ $htmlSourceToFetchFrom = preg_replace( array('@<(style|script|noscript)[^>]*?>.*?</\\1>@si', '#<(meta|img)([^<>]+)/?>#iU'), '', $htmlSourceToFetchFrom );
363
+ } else {
364
+ // Strip NOSCRIPT tags
365
+ $htmlSourceToFetchFrom = preg_replace( '@<(noscript)[^>]*?>.*?</\\1>@si', '', $htmlSourceToFetchFrom );
366
+ }
367
 
368
  // Case: Return the HTML source without any conditional comments and the content within them
369
  if (in_array('strip_content_between_conditional_comments', $params)) {
370
+ preg_match_all('#<!--\[if(.*?)]>(<!-->|-->|\s|)(.*?)(<!--<!|<!)\[endif]-->#si', $htmlSourceToFetchFrom, $matchedContent);
371
 
372
  if (isset($matchedContent[0]) && ! empty($matchedContent[0])) {
373
  foreach ($matchedContent[0] as $conditionalHtmlContent) {
374
+ $htmlSourceToFetchFrom = str_replace($conditionalHtmlContent, '', $htmlSourceToFetchFrom);
375
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
 
377
+ return $htmlSourceToFetchFrom;
 
 
 
 
 
378
  }
 
 
379
  }
380
 
381
+ return $htmlSourceToFetchFrom;
 
 
 
 
 
 
 
382
  }
383
 
384
  /**
920
  *
921
  * @param bool $redirectAfter
922
  */
923
+ public static function clearCache($redirectAfter = false)
924
  {
925
+ if (self::doNotClearCache()) {
926
  return;
927
  }
928
 
1103
  @rmdir(WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir().'one');
1104
  @rmdir(WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir().'one');
1105
 
1106
+
1107
+ /*
1108
+ * Special Case: Any CSS/JS files from /wp-content/cache//asset-cleanup/(css|js)/item/inline/
1109
+ * These files are never loaded as static, externally (from LINK or SCRIPT tag);
1110
+ * Their content is just pulled (if not expired) into the STYLE/SCRIPT inline tag
1111
+ * If there are any expired files there, remove them
1112
+ */
1113
+ foreach (array('.css', '.js') as $assetExt) {
1114
+ $assetTypeDir = ($assetExt === '.css') ? OptimizeCss::getRelPathCssCacheDir() : OptimizeJs::getRelPathJsCacheDir();
1115
+
1116
+ $assetsInlineTagsContentDir = WP_CONTENT_DIR . $assetTypeDir . self::$optimizedSingleFilesDir . '/inline/';
1117
+
1118
+ if ( is_dir( $assetsInlineTagsContentDir ) ) {
1119
+ $assetInlineTagsContentDirFiles = scandir( $assetsInlineTagsContentDir );
1120
+
1121
+ foreach ( $assetInlineTagsContentDirFiles as $assetFile ) {
1122
+ if ( strpos( $assetFile, $assetExt ) === false ) {
1123
+ continue;
1124
+ }
1125
+
1126
+ $fullPathToFile = $assetsInlineTagsContentDir . $assetFile;
1127
+
1128
+ $isExpired = ( filemtime( $fullPathToFile ) < ( time() - 1 * self::$cachedAssetFileExpiresIn ) );
1129
+
1130
+ if ( $isExpired ) {
1131
+ @unlink( $fullPathToFile );
1132
+ }
1133
+ }
1134
+
1135
+ }
1136
+ }
1137
+
1138
  /*
1139
  * STEP 2: Remove all transients related to the Minify CSS/JS files feature
1140
  */
1166
  }
1167
  }
1168
 
1169
+ /**
1170
+ * Alias for clearCache() - some developers might have implemented clearAllCache()
1171
+ *
1172
+ * @param bool $redirectAfter
1173
+ */
1174
+ public static function clearAllCache($redirectAfter = false)
1175
+ {
1176
+ self::clearCache($redirectAfter);
1177
+ }
1178
+
1179
  /**
1180
  * This is usually done when the plugin is deactivated
1181
  * e.g. if you use Autoptimize and it remains active, you will likely want to have its caching cleared with traces from Asset CleanUp
1239
  *
1240
  * @return bool
1241
  */
1242
+ public static function doNotClearCache()
1243
  {
1244
  // WooCommerce GET or AJAX call
1245
  if (array_key_exists('wc-ajax', $_GET) && $_GET['wc-ajax']) {
1315
  */
1316
  public static function stripSourceMap($assetContent)
1317
  {
1318
+ return str_replace('# sourceMappingURL=', '# Original Source Map: ', $assetContent);
1319
  }
1320
 
1321
  /**
1331
 
1332
  $ignoreQueryStrings = array(
1333
  'wpacu_do_combine', // show the CSS/JS as combined IF the option is enabled despite the query string (for debugging purposes)
1334
+ 'wpacu_no_css_minify', 'wpacu_no_js_minify', 'wpacu_no_css_combine', 'wpacu_no_js_combine', 'wpacu_debug', 'wpacu_preload', 'wpacu_skip_test_mode',
1335
  'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_expid', 'utm_referrer', // Google Analytics
1336
  'gclid', // Google Click ID
1337
  'fbclick', 'fbclid', 'fb_action_ids', 'fb_action_types', 'fb_source', // Facebook
1555
  @rmdir($targetDir);
1556
  }
1557
  }
1558
+
1559
+ /**
1560
+ * @param $assetContentSha1
1561
+ * @param $assetType
1562
+ *
1563
+ * @return bool
1564
+ */
1565
+ public static function originalContentIsAlreadyMarkedAsMinified($assetContentSha1, $assetType)
1566
+ {
1567
+ $optionToCheck = WPACU_PLUGIN_ID . '_global_data';
1568
+ $globalKey = 'already_minified'; // HEAD or BODY
1569
+
1570
+ $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1571
+ $existingListJson = get_option($optionToCheck);
1572
+
1573
+ $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1574
+ $existingList = $existingListData['list'];
1575
+
1576
+ return isset( $existingList[ $assetType ]['already_minified'] ) && in_array( $assetContentSha1, $existingList[ $assetType ]['already_minified'] );
1577
+ }
1578
+
1579
+ /**
1580
+ * @param $assetContentSha1
1581
+ * @param $assetType
1582
+ */
1583
+ public static function originalContentMarkAsAlreadyMinified($assetContentSha1, $assetType)
1584
+ {
1585
+ $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1586
+ $globalKey = 'already_minified'; // HEAD or BODY
1587
+
1588
+ $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1589
+ $existingListJson = get_option($optionToUpdate);
1590
+
1591
+ $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1592
+ $existingList = $existingListData['list'];
1593
+
1594
+ if (! isset($existingList[$assetType]['already_minified'])) {
1595
+ $existingList[$assetType]['already_minified'] = array();
1596
+ }
1597
+
1598
+ $existingList[$assetType]['already_minified'][] = $assetContentSha1;
1599
+
1600
+ update_option($optionToUpdate, json_encode(Misc::filterList($existingList)));
1601
+ }
1602
+
1603
+ }
classes/OptimiseAssets/OptimizeCss.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  namespace WpAssetCleanUp\OptimiseAssets;
3
 
 
4
  use WpAssetCleanUp\Plugin;
5
  use WpAssetCleanUp\Preloads;
6
  use WpAssetCleanUp\FileSystem;
@@ -26,7 +27,11 @@ class OptimizeCss
26
  public function init()
27
  {
28
  add_action('init', array($this, 'triggersAfterInit'));
29
- add_action('wp_footer', array($this, 'prepareOptimizeList'), PHP_INT_MAX);
 
 
 
 
30
 
31
  add_action('wp_footer', static function() {
32
  if ( Plugin::preventAnyChanges() || Main::isTestModeActive() ) {
@@ -95,7 +100,7 @@ class OptimizeCss
95
  /**
96
  *
97
  */
98
- public function prepareOptimizeList()
99
  {
100
  if ( ! self::isWorthCheckingForOptimization() || Plugin::preventAnyChanges() ) {
101
  return;
@@ -103,7 +108,7 @@ class OptimizeCss
103
 
104
  global $wp_styles;
105
 
106
- $allStylesHandles = wp_cache_get('wpacu_all_styles_handles');
107
  if (empty($allStylesHandles)) {
108
  return;
109
  }
@@ -138,7 +143,7 @@ class OptimizeCss
138
  $cssOptimizeList = array();
139
 
140
  foreach ($wpStylesDone as $handle) {
141
- if (! isset($wpStylesRegistered[$handle])) {
142
  continue;
143
  }
144
 
@@ -150,6 +155,7 @@ class OptimizeCss
150
  }
151
 
152
  $optimizeValues = self::maybeOptimizeIt($value);
 
153
 
154
  if (! empty($optimizeValues)) {
155
  $cssOptimizeList[] = $optimizeValues;
@@ -160,8 +166,8 @@ class OptimizeCss
160
  return;
161
  }
162
 
163
- wp_cache_add('wpacu_css_enqueued_hrefs', $allEnqueuedCleanLinkHrefs);
164
- wp_cache_add('wpacu_css_optimize_list', $cssOptimizeList);
165
  // [End] Collect for caching
166
  }
167
 
@@ -172,6 +178,10 @@ class OptimizeCss
172
  */
173
  public static function maybeOptimizeIt($value)
174
  {
 
 
 
 
175
  global $wp_version;
176
 
177
  $src = isset($value->src) ? $value->src : false;
@@ -188,13 +198,20 @@ class OptimizeCss
188
  $doFileMinify = false;
189
  }
190
 
191
- $fileVer = $dbVer = (isset($value->ver) && $value->ver) ? $value->ver : $wp_version;
192
 
193
  $handleDbStr = md5($value->handle);
194
 
195
  $transientName = 'wpacu_css_optimize_'.$handleDbStr;
196
 
197
- if (Main::instance()->settings['fetch_cached_files_details_from'] === 'db_disk') {
 
 
 
 
 
 
 
198
  if ( ! isset( $GLOBALS['wpacu_from_location_inc'] ) ) {
199
  $GLOBALS['wpacu_from_location_inc'] = 1;
200
  }
@@ -222,7 +239,8 @@ class OptimizeCss
222
  return array(
223
  $savedValuesArray['source_uri'],
224
  $savedValuesArray['optimize_uri'],
225
- $value->src
 
226
  );
227
  }
228
 
@@ -230,6 +248,8 @@ class OptimizeCss
230
  OptimizeCommon::deleteTransient($transientName);
231
  }
232
  }
 
 
233
  // Check if it starts without "/" or a protocol; e.g. "wp-content/theme/style.css"
234
  if (strpos($src, '/') !== 0 &&
235
  strpos($src, '//') !== 0 &&
@@ -285,42 +305,67 @@ class OptimizeCss
285
  $sourceBeforeOptimization = str_replace(ABSPATH, '/', $localAssetPath);
286
  }
287
 
 
 
288
  /*
289
  * [START] CSS Content Optimization
290
  */
291
- // If there are no changes from this point, do not optimize (keep the file where it is)
292
- $cssContentBefore = $cssContent;
293
 
294
- if (Main::instance()->settings['google_fonts_display']) {
 
295
  // Any "font-display" enabled in "Settings" - "Google Fonts"?
296
- $cssContent = FontsGoogle::alterGoogleFontUrlFromCssContent($cssContent);
297
  }
298
 
299
  // Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
300
- $cssContent = self::importsUpdate($cssContent);
 
 
 
 
 
 
 
 
 
 
 
301
 
302
- if ($doFileMinify) {
303
- // Minify this file?
304
- $cssContent = MinifyCss::applyMinification($cssContent) ?: $cssContent;
305
  }
 
306
 
307
- if (Main::instance()->settings['google_fonts_remove']) {
308
- $cssContent = FontsGoogleRemove::cleanFontFaceReferences($cssContent);
 
 
 
309
  }
310
 
311
  // No changes were made, thus, there's no point in changing the original file location
312
- if ($isCssFile && trim($cssContentBefore) === trim($cssContent)) {
313
  // There's no point in changing the original CSS (static) file location
314
  return false;
315
  }
316
 
317
- $cssContent = self::maybeFixCssContent($cssContent, $pathToAssetDir . '/'); // Path
 
 
 
 
 
 
318
  /*
319
  * [END] CSS Content Optimization
320
  */
321
 
322
  // Relative path to the new file
323
  // Save it to /wp-content/cache/css/{OptimizeCommon::$optimizedSingleFilesDir}/
 
324
  if ($fileVer !== $wp_version) {
325
  if (is_array($fileVer)) {
326
  // Convert to string if it's an array (rare cases)
@@ -329,24 +374,26 @@ class OptimizeCss
329
  $fileVer = trim(str_replace(' ', '_', preg_replace('/\s+/', ' ', $fileVer)));
330
  $fileVer = (strlen($fileVer) > 50) ? substr(md5($fileVer), 0, 20) : $fileVer; // don't end up with too long filenames
331
  }
 
 
332
 
333
  $newFilePathUri = self::getRelPathCssCacheDir() . OptimizeCommon::$optimizedSingleFilesDir . '/' . $value->handle . '-v' . $fileVer;
 
334
 
335
- if (isset($localAssetPath)) { // could be from "/?custom-css=" so a check is needed
336
- $sha1File = @sha1_file($localAssetPath);
337
-
338
- if ($sha1File) {
339
- $newFilePathUri .= '-' . $sha1File;
340
- }
341
  }
342
 
343
- $newFilePathUri .= '.css';
 
 
 
344
 
345
  $newLocalPath = WP_CONTENT_DIR . $newFilePathUri; // Ful Local path
346
  $newLocalPathUrl = WP_CONTENT_URL . $newFilePathUri; // Full URL path
347
 
348
- if ($cssContent) {
349
- $cssContent = '/*! ' . $sourceBeforeOptimization . ' */' . $cssContent;
350
  }
351
 
352
  $saveFile = FileSystem::file_put_contents($newLocalPath, $cssContent);
@@ -368,7 +415,8 @@ class OptimizeCss
368
  return array(
369
  OptimizeCommon::getSourceRelPath($src), // Original SRC (Relative path)
370
  OptimizeCommon::getSourceRelPath($newLocalPathUrl), // New SRC (Relative path)
371
- $value->src // SRC (as it is)
 
372
  );
373
  }
374
 
@@ -440,7 +488,7 @@ class OptimizeCss
440
 
441
  // Final cleanups
442
  $htmlSource = preg_replace('#<link(\s+|)data-wpacu-link-rel-href-before=(["\'])' . '(.*)' . '(\1)#Usmi', '<link ', $htmlSource);
443
- $htmlSource = preg_replace('#<link(.*)data-wpacu-style-handle=\'(.*)\'#Umi', '<link \\1', $htmlSource);
444
 
445
  /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_google_fonts_optimization_removal'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
446
  // Alter HTML Source for Google Fonts Optimization / Removal
@@ -452,7 +500,6 @@ class OptimizeCss
452
  $htmlSource = apply_filters('wpacu_add_async_preloads_noscript', $htmlSource);
453
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
454
 
455
- // Final timing (for the whole HTML source)
456
  /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_optimize_css', 'end'); /* [/wpacu_timing] */
457
 
458
  return $htmlSource;
@@ -474,7 +521,7 @@ class OptimizeCss
474
  */
475
  public static function getFirstLinkTag($firstLinkHref, $htmlSource)
476
  {
477
- preg_match_all('#<link[^>]*stylesheet[^>]*(>)#Usmi', $htmlSource, $matches);
478
  foreach ($matches[0] as $matchTag) {
479
  if (strpos($matchTag, $firstLinkHref) !== false) {
480
  return trim($matchTag);
@@ -580,53 +627,64 @@ class OptimizeCss
580
  */
581
  public static function updateHtmlSourceOriginalToOptimizedCss($htmlSource)
582
  {
583
- $cssOptimizeList = wp_cache_get('wpacu_css_optimize_list') ?: array();
584
- $allEnqueuedCleanLinkHrefs = wp_cache_get('wpacu_css_enqueued_hrefs') ?: array();
 
 
 
 
 
585
 
586
  $cdnUrls = OptimizeCommon::getAnyCdnUrls();
587
  $cdnUrlForCss = isset($cdnUrls['css']) ? $cdnUrls['css'] : false;
588
 
589
- preg_match_all('#<link[^>]*(stylesheet|(as(\s+|)=(\s+|)(|"|\')style(|"|\')))[^>]*(>)#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
590
 
591
  if (empty($matchesSourcesFromTags)) {
592
  return $htmlSource;
593
  }
594
 
 
 
595
  foreach ($matchesSourcesFromTags as $matches) {
596
  $linkSourceTag = $matches[0];
597
 
598
- if (strip_tags($linkSourceTag) !== '') {
599
  // Hmm? Not a valid tag... Skip it...
600
  continue;
601
  }
602
 
 
 
 
 
 
 
 
603
  // Is it a local CSS? Check if it's hardcoded (not enqueued the WordPress way)
604
- if ($cleanLinkHrefFromTagArray = OptimizeCommon::getLocalCleanSourceFromTag($linkSourceTag, 'href')) {
605
- $cleanLinkHrefFromTag = $cleanLinkHrefFromTagArray['source'];
606
- $afterQuestionMark = $cleanLinkHrefFromTagArray['after_question_mark'];
607
-
608
- if (! in_array($cleanLinkHrefFromTag, $allEnqueuedCleanLinkHrefs)) {
609
- // Not in the final enqueued list? Most likely hardcoded (not added via wp_enqueue_scripts())
610
- // Emulate the object value (as the enqueued styles)
611
- $value = (object)array(
612
- 'handle' => md5($cleanLinkHrefFromTag),
613
- 'src' => $cleanLinkHrefFromTag,
614
- 'ver' => md5($afterQuestionMark)
615
- );
 
616
 
617
- $optimizeValues = self::maybeOptimizeIt($value);
 
618
 
619
- if (! empty($optimizeValues)) {
620
- $cssOptimizeList[] = $optimizeValues;
621
- }
622
  }
623
  }
624
 
625
- if (empty($cssOptimizeList)) {
626
- continue;
627
- }
628
-
629
- foreach ($cssOptimizeList as $listValues) {
630
  // Index 0: Source URL (relative)
631
  // Index 1: New Optimized URL (relative)
632
  // Index 2: Source URL (as it is)
@@ -635,7 +693,9 @@ class OptimizeCss
635
 
636
  // If the minified files are deleted (e.g. /wp-content/cache/ is cleared)
637
  // do not replace the CSS file path to avoid breaking the website
638
- if (! is_file(rtrim(ABSPATH, '/') . $listValues[1])) {
 
 
639
  continue;
640
  }
641
 
@@ -667,14 +727,33 @@ class OptimizeCss
667
  // If no CDN is set, it will return site_url() as a prefix
668
  $optimizeUrl = OptimizeCommon::cdnToUrlFormat($cdnUrlForCss, 'raw') . $listValues[1]; // string
669
 
670
- if ($linkSourceTag !== str_ireplace($sourceUrlList, $optimizeUrl, $linkSourceTag)) {
671
- $newLinkSourceTag = self::updateOriginalToOptimizedTag($linkSourceTag, $sourceUrlList, $optimizeUrl);
672
- $htmlSource = str_replace($linkSourceTag, $newLinkSourceTag, $htmlSource);
673
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  }
675
  }
676
  }
677
 
 
 
678
  return $htmlSource;
679
  }
680
 
@@ -724,6 +803,8 @@ class OptimizeCss
724
  }
725
 
726
  /**
 
 
727
  * @param $htmlSource
728
  *
729
  * @return mixed
@@ -733,9 +814,13 @@ class OptimizeCss
733
  $allPatterns = self::getAllInlineChosenPatterns();
734
 
735
  // Skip any LINK tags within conditional comments (e.g. Internet Explorer ones)
736
- preg_match_all( '#<link[^>]*stylesheet[^>]*(>)#Umi',
737
- OptimizeCommon::cleanerHtmlSource( $htmlSource, array( 'strip_content_between_conditional_comments' ) ),
738
- $matchesSourcesFromTags, PREG_SET_ORDER );
 
 
 
 
739
  // In case automatic inlining is used
740
  $belowSizeInput = (int)Main::instance()->settings['inline_css_files_below_size_input'];
741
 
@@ -750,9 +835,12 @@ class OptimizeCss
750
  foreach ($matchesSourcesFromTags as $matchList) {
751
  $matchedTag = $matchList[0];
752
 
 
 
 
 
753
  // They were preloaded for a reason, leave them
754
- if (strpos($matchedTag, 'data-wpacu-preload-it-async=') !== false
755
- || strpos($matchedTag, 'data-wpacu-to-be-preloaded-basic=') !== false) {
756
  continue;
757
  }
758
 
@@ -761,8 +849,7 @@ class OptimizeCss
761
  }
762
 
763
  // Condition #1: Only chosen (via textarea) CSS get inlined
764
- $chosenInlineCssMatches = (! empty($allPatterns) &&
765
- preg_match('/(' . implode('|', $allPatterns) . ')/i', $matchedTag));
766
 
767
  // Is auto inline disabled and the chosen CSS does not match? Continue to the next LINK tag
768
  if (! $chosenInlineCssMatches && ! self::isAutoInlineEnabled()) {
@@ -802,7 +889,7 @@ class OptimizeCss
802
  // The CSS file is read from its original plugin/theme/cache location
803
  // If minify was enabled, then it's already minified, no point in re-minify it to save resources
804
  // Changing paths (relative) to fonts, images, etc. are relevant in this case
805
- $cssContent = self::maybeAlterCssContent($cssContent, false, false);
806
 
807
  if ($cssContent && $cssContent !== '/**/') {
808
  $htmlSource = str_replace(
@@ -826,32 +913,113 @@ class OptimizeCss
826
  *
827
  * @param $cssContent
828
  * @param bool $doCssMinify (false by default as it could be already minified or non-minify type)
829
- * @param bool $forInlineStyle - (false by default - this param is relevant only for inline tags that are altered "on the fly")
830
- *
831
  * @param array $extraParams
832
  *
833
  * @return mixed|string|string[]|null
834
  */
835
- public static function maybeAlterCssContent($cssContent, $doCssMinify = false, $forInlineStyle = false, $extraParams = array())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836
  {
837
  if (! trim($cssContent)) {
838
  return $cssContent;
839
  }
840
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
  if ( $doCssMinify && in_array('just_minify', $extraParams) ) {
842
- $cssContent = MinifyCss::applyMinification( $cssContent, $forInlineStyle );
843
  } else {
844
  // Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
845
  $cssContent = self::importsUpdate( $cssContent );
846
 
847
  if ( $doCssMinify ) {
848
- $cssContent = MinifyCss::applyMinification( $cssContent, $forInlineStyle );
849
  }
850
 
851
  if ( Main::instance()->settings['google_fonts_remove'] ) {
852
  $cssContent = FontsGoogleRemove::cleanFontFaceReferences( $cssContent );
853
  }
854
  }
 
 
 
 
 
 
855
 
856
  return $cssContent;
857
  }
@@ -1079,6 +1247,11 @@ class OptimizeCss
1079
 
1080
  if (isset($ignoreChild['styles']) && ! empty($ignoreChild['styles'])) {
1081
  foreach (array_keys($ignoreChild['styles']) as $styleHandle) {
 
 
 
 
 
1082
  if (isset(Main::instance()->wpAllStyles['registered'][$styleHandle]->src, Main::instance()->ignoreChildren['styles'][$styleHandle.'_has_unload_rule']) && Main::instance()->wpAllStyles['registered'][$styleHandle]->src && Main::instance()->ignoreChildren['styles'][$styleHandle.'_has_unload_rule']) {
1083
  if ($scriptExtraAfterHtml = self::generateInlineAssocHtmlForHandle($styleHandle)) {
1084
  $htmlSource = str_replace($scriptExtraAfterHtml, '', $htmlSource);
1
  <?php
2
  namespace WpAssetCleanUp\OptimiseAssets;
3
 
4
+ use WpAssetCleanUp\ObjectCache;
5
  use WpAssetCleanUp\Plugin;
6
  use WpAssetCleanUp\Preloads;
7
  use WpAssetCleanUp\FileSystem;
27
  public function init()
28
  {
29
  add_action('init', array($this, 'triggersAfterInit'));
30
+ add_action('wp_footer', static function() {
31
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'prepare_optimize_files_css' ); /* [/wpacu_timing] */
32
+ self::prepareOptimizeList();
33
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'prepare_optimize_files_css', 'end' ); /* [/wpacu_timing] */
34
+ }, PHP_INT_MAX);
35
 
36
  add_action('wp_footer', static function() {
37
  if ( Plugin::preventAnyChanges() || Main::isTestModeActive() ) {
100
  /**
101
  *
102
  */
103
+ public static function prepareOptimizeList()
104
  {
105
  if ( ! self::isWorthCheckingForOptimization() || Plugin::preventAnyChanges() ) {
106
  return;
108
 
109
  global $wp_styles;
110
 
111
+ $allStylesHandles = ObjectCache::wpacu_cache_get('wpacu_all_styles_handles');
112
  if (empty($allStylesHandles)) {
113
  return;
114
  }
143
  $cssOptimizeList = array();
144
 
145
  foreach ($wpStylesDone as $handle) {
146
+ if (! isset($wpStylesRegistered[$handle]->src)) {
147
  continue;
148
  }
149
 
155
  }
156
 
157
  $optimizeValues = self::maybeOptimizeIt($value);
158
+ ObjectCache::wpacu_cache_set('wpacu_maybe_optimize_it_css_'.$handle, $optimizeValues);
159
 
160
  if (! empty($optimizeValues)) {
161
  $cssOptimizeList[] = $optimizeValues;
166
  return;
167
  }
168
 
169
+ ObjectCache::wpacu_cache_add('wpacu_css_enqueued_hrefs', $allEnqueuedCleanLinkHrefs);
170
+ ObjectCache::wpacu_cache_add('wpacu_css_optimize_list', $cssOptimizeList);
171
  // [End] Collect for caching
172
  }
173
 
178
  */
179
  public static function maybeOptimizeIt($value)
180
  {
181
+ if ($optimizeValues = ObjectCache::wpacu_cache_get('wpacu_maybe_optimize_it_css_'.$value->handle)) {
182
+ return $optimizeValues;
183
+ }
184
+
185
  global $wp_version;
186
 
187
  $src = isset($value->src) ? $value->src : false;
198
  $doFileMinify = false;
199
  }
200
 
201
+ $dbVer = (isset($value->ver) && $value->ver) ? $value->ver : $wp_version;
202
 
203
  $handleDbStr = md5($value->handle);
204
 
205
  $transientName = 'wpacu_css_optimize_'.$handleDbStr;
206
 
207
+ $skipCache = false;
208
+
209
+ if (isset($_GET['wpacu_no_cache'])) {
210
+ $skipCache = true;
211
+ }
212
+
213
+ if (! $skipCache) {
214
+ if (Main::instance()->settings['fetch_cached_files_details_from'] === 'db_disk') {
215
  if ( ! isset( $GLOBALS['wpacu_from_location_inc'] ) ) {
216
  $GLOBALS['wpacu_from_location_inc'] = 1;
217
  }
239
  return array(
240
  $savedValuesArray['source_uri'],
241
  $savedValuesArray['optimize_uri'],
242
+ $value->src,
243
+ $value->handle
244
  );
245
  }
246
 
248
  OptimizeCommon::deleteTransient($transientName);
249
  }
250
  }
251
+ }
252
+
253
  // Check if it starts without "/" or a protocol; e.g. "wp-content/theme/style.css"
254
  if (strpos($src, '/') !== 0 &&
255
  strpos($src, '//') !== 0 &&
305
  $sourceBeforeOptimization = str_replace(ABSPATH, '/', $localAssetPath);
306
  }
307
 
308
+ $cssContent = trim($cssContent);
309
+
310
  /*
311
  * [START] CSS Content Optimization
312
  */
313
+ // If there are no changes from this point, do not optimize (keep the file where it is)
314
+ $cssContentBefore = $cssContent;
315
 
316
+ if ($cssContent) { // only proceed with extra alterations if there is some content there (save resources)
317
+ if ( Main::instance()->settings['google_fonts_display'] ) {
318
  // Any "font-display" enabled in "Settings" - "Google Fonts"?
319
+ $cssContent = FontsGoogle::alterGoogleFontUrlFromCssContent( $cssContent );
320
  }
321
 
322
  // Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
323
+ $cssContent = self::importsUpdate( $cssContent );
324
+ }
325
+
326
+ // If it stays like this, it means there is content there, even if only comments
327
+ $cssContentBecomesEmptyAfterMin = false;
328
+
329
+ if ($doFileMinify && $cssContent) { // only bother to minify it if it has any content, save resources
330
+ // Minify this file?
331
+ $cssContentBeforeMin = trim($cssContent);
332
+ $cssContentAfterMin = MinifyCss::applyMinification($cssContent);
333
+
334
+ $cssContent = $cssContentAfterMin;
335
 
336
+ if ($cssContentBeforeMin && $cssContentAfterMin === '') {
337
+ // It had content, but became empty after minification, most likely it had only comments (e.g. a default child theme's style)
338
+ $cssContentBecomesEmptyAfterMin = true;
339
  }
340
+ }
341
 
342
+ if ($cssContentBecomesEmptyAfterMin || $cssContent === '') {
343
+ $cssContent = '/**/';
344
+ } else {
345
+ if ( Main::instance()->settings['google_fonts_remove'] ) {
346
+ $cssContent = FontsGoogleRemove::cleanFontFaceReferences( $cssContent );
347
  }
348
 
349
  // No changes were made, thus, there's no point in changing the original file location
350
+ if ( $isCssFile && ! $cssContentBecomesEmptyAfterMin && trim( $cssContentBefore ) === trim( $cssContent ) ) {
351
  // There's no point in changing the original CSS (static) file location
352
  return false;
353
  }
354
 
355
+ // Does it have a source map? Strip it
356
+ if (strpos($cssContent, 'sourceMappingURL') !== false) {
357
+ $cssContent = OptimizeCommon::stripSourceMap($cssContent);
358
+ }
359
+
360
+ $cssContent = self::maybeFixCssContent( $cssContent, $pathToAssetDir . '/' ); // Path
361
+ }
362
  /*
363
  * [END] CSS Content Optimization
364
  */
365
 
366
  // Relative path to the new file
367
  // Save it to /wp-content/cache/css/{OptimizeCommon::$optimizedSingleFilesDir}/
368
+ /*
369
  if ($fileVer !== $wp_version) {
370
  if (is_array($fileVer)) {
371
  // Convert to string if it's an array (rare cases)
374
  $fileVer = trim(str_replace(' ', '_', preg_replace('/\s+/', ' ', $fileVer)));
375
  $fileVer = (strlen($fileVer) > 50) ? substr(md5($fileVer), 0, 20) : $fileVer; // don't end up with too long filenames
376
  }
377
+ */
378
+ $fileVer = sha1($cssContent);
379
 
380
  $newFilePathUri = self::getRelPathCssCacheDir() . OptimizeCommon::$optimizedSingleFilesDir . '/' . $value->handle . '-v' . $fileVer;
381
+ $newFilePathUri .= '.css';
382
 
383
+ if ($cssContent === '') {
384
+ $cssContent = '/**/';
 
 
 
 
385
  }
386
 
387
+ if ($cssContent === '/**/') {
388
+ // Leave a signature that the file is empty, thus it would be faster to take further actions upon it later on, saving resources)
389
+ $newFilePathUri = str_replace('.css', '-wpacu-empty-file.css', $newFilePathUri);
390
+ }
391
 
392
  $newLocalPath = WP_CONTENT_DIR . $newFilePathUri; // Ful Local path
393
  $newLocalPathUrl = WP_CONTENT_URL . $newFilePathUri; // Full URL path
394
 
395
+ if ($cssContent && $cssContent !== '/**/') {
396
+ $cssContent = '/*!' . $sourceBeforeOptimization . '*/' . $cssContent;
397
  }
398
 
399
  $saveFile = FileSystem::file_put_contents($newLocalPath, $cssContent);
415
  return array(
416
  OptimizeCommon::getSourceRelPath($src), // Original SRC (Relative path)
417
  OptimizeCommon::getSourceRelPath($newLocalPathUrl), // New SRC (Relative path)
418
+ $value->src, // SRC (as it is)
419
+ $value->handle
420
  );
421
  }
422
 
488
 
489
  // Final cleanups
490
  $htmlSource = preg_replace('#<link(\s+|)data-wpacu-link-rel-href-before=(["\'])' . '(.*)' . '(\1)#Usmi', '<link ', $htmlSource);
491
+ //$htmlSource = preg_replace('#<link(.*)data-wpacu-style-handle=\'(.*)\'#Umi', '<link \\1', $htmlSource);
492
 
493
  /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_google_fonts_optimization_removal'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
494
  // Alter HTML Source for Google Fonts Optimization / Removal
500
  $htmlSource = apply_filters('wpacu_add_async_preloads_noscript', $htmlSource);
501
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
502
 
 
503
  /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_optimize_css', 'end'); /* [/wpacu_timing] */
504
 
505
  return $htmlSource;
521
  */
522
  public static function getFirstLinkTag($firstLinkHref, $htmlSource)
523
  {
524
+ preg_match_all('#<link[^>]*stylesheet[^>]*(>)#Umi', $htmlSource, $matches);
525
  foreach ($matches[0] as $matchTag) {
526
  if (strpos($matchTag, $firstLinkHref) !== false) {
527
  return trim($matchTag);
627
  */
628
  public static function updateHtmlSourceOriginalToOptimizedCss($htmlSource)
629
  {
630
+ $cssOptimizeList = ObjectCache::wpacu_cache_get('wpacu_css_optimize_list') ?: array();
631
+
632
+ if (empty($cssOptimizeList)) {
633
+ return $htmlSource;
634
+ }
635
+
636
+ $allEnqueuedCleanLinkHrefs = ObjectCache::wpacu_cache_get('wpacu_css_enqueued_hrefs') ?: array();
637
 
638
  $cdnUrls = OptimizeCommon::getAnyCdnUrls();
639
  $cdnUrlForCss = isset($cdnUrls['css']) ? $cdnUrls['css'] : false;
640
 
641
+ preg_match_all('#<link[^>]*(stylesheet|(as(\s+|)=(\s+|)(|"|\')style(|"|\')))[^>]*>#Umi', OptimizeCommon::cleanerHtmlSource( $htmlSource, array( 'for_fetching_link_tags' ) ), $matchesSourcesFromTags, PREG_SET_ORDER);
642
 
643
  if (empty($matchesSourcesFromTags)) {
644
  return $htmlSource;
645
  }
646
 
647
+ $linkTagsToUpdate = array();
648
+
649
  foreach ($matchesSourcesFromTags as $matches) {
650
  $linkSourceTag = $matches[0];
651
 
652
+ if ($linkSourceTag === '' || strip_tags($linkSourceTag) !== '') {
653
  // Hmm? Not a valid tag... Skip it...
654
  continue;
655
  }
656
 
657
+ $cleanLinkHrefFromTagArray = OptimizeCommon::getLocalCleanSourceFromTag($linkSourceTag, 'href');
658
+
659
+ // Skip external links, no point in carrying on
660
+ if (! $cleanLinkHrefFromTagArray || ! is_array($cleanLinkHrefFromTagArray)) {
661
+ continue;
662
+ }
663
+
664
  // Is it a local CSS? Check if it's hardcoded (not enqueued the WordPress way)
665
+ $cleanLinkHrefFromTag = $cleanLinkHrefFromTagArray['source'];
666
+ $afterQuestionMark = $cleanLinkHrefFromTagArray['after_question_mark'];
667
+
668
+ if (! in_array($cleanLinkHrefFromTag, $allEnqueuedCleanLinkHrefs)) {
669
+ // Not in the final enqueued list? Most likely hardcoded (not added via wp_enqueue_scripts())
670
+ // Emulate the object value (as the enqueued styles)
671
+ $generatedHandle = md5($cleanLinkHrefFromTag);
672
+
673
+ $value = (object)array(
674
+ 'handle' => $generatedHandle,
675
+ 'src' => $cleanLinkHrefFromTag,
676
+ 'ver' => md5($afterQuestionMark)
677
+ );
678
 
679
+ $optimizeValues = self::maybeOptimizeIt($value);
680
+ ObjectCache::wpacu_cache_set('wpacu_maybe_optimize_it_css_'.$generatedHandle, $optimizeValues);
681
 
682
+ if (! empty($optimizeValues)) {
683
+ $cssOptimizeList[] = $optimizeValues;
 
684
  }
685
  }
686
 
687
+ foreach ($cssOptimizeList as $cssItemIndex => $listValues) {
 
 
 
 
688
  // Index 0: Source URL (relative)
689
  // Index 1: New Optimized URL (relative)
690
  // Index 2: Source URL (as it is)
693
 
694
  // If the minified files are deleted (e.g. /wp-content/cache/ is cleared)
695
  // do not replace the CSS file path to avoid breaking the website
696
+ $localPathOptimizedFile = rtrim(ABSPATH, '/') . $listValues[1];
697
+
698
+ if (! is_file($localPathOptimizedFile)) {
699
  continue;
700
  }
701
 
727
  // If no CDN is set, it will return site_url() as a prefix
728
  $optimizeUrl = OptimizeCommon::cdnToUrlFormat($cdnUrlForCss, 'raw') . $listValues[1]; // string
729
 
730
+ if ($linkSourceTag !== str_replace($sourceUrlList, $optimizeUrl, $linkSourceTag)) {
731
+ // Extra measure: Check the file size which should be 4 bytes, but add some margin error in case some environments will report less
732
+ $isEmptyOptimizedFile = (strpos($localPathOptimizedFile, '-wpacu-empty-file.css') !== false && filesize($localPathOptimizedFile) < 10);
733
+
734
+ // Strip it as its content (after optimization, for instance) is empty; no point in having extra HTTP requests
735
+ if ($isEmptyOptimizedFile) {
736
+ $htmlSourceBefore = $htmlSource;
737
+ $htmlSource = str_replace($linkSourceTag, '', $htmlSource);
738
+ $htmlSourceAfter = $htmlSource;
739
+
740
+ if ( ( $htmlSourceAfter !== $htmlSourceBefore ) && $scriptExtraAfterHtml = self::generateInlineAssocHtmlForHandle( $listValues[3] ) ) {
741
+ $htmlSource = str_replace( $scriptExtraAfterHtml, '', $htmlSource );
742
+ }
743
+ } else {
744
+ // Do the replacement
745
+ $newLinkSourceTag = self::updateOriginalToOptimizedTag( $linkSourceTag, $sourceUrlList, $optimizeUrl );
746
+ $linkTagsToUpdate[$linkSourceTag] = $newLinkSourceTag;
747
+ }
748
+
749
+ unset($cssOptimizeList[$cssItemIndex]); // item from the array is not needed anymore
750
+ break; // there was a match, stop here
751
  }
752
  }
753
  }
754
 
755
+ $htmlSource = strtr($htmlSource, $linkTagsToUpdate);
756
+
757
  return $htmlSource;
758
  }
759
 
803
  }
804
 
805
  /**
806
+ * From LINK to STYLE tag: it processes the contents of the LINK stylesheet and replaces the tag with a STYLE tag having the content inlined
807
+ *
808
  * @param $htmlSource
809
  *
810
  * @return mixed
814
  $allPatterns = self::getAllInlineChosenPatterns();
815
 
816
  // Skip any LINK tags within conditional comments (e.g. Internet Explorer ones)
817
+ preg_match_all(
818
+ '#<link[^>]*rel=([\'"])stylesheet([\'"])[^>]*href.*>#Usmi',
819
+ OptimizeCommon::cleanerHtmlSource( $htmlSource, array( 'strip_content_between_conditional_comments', 'for_fetching_link_tags' ) ),
820
+ $matchesSourcesFromTags,
821
+ PREG_SET_ORDER
822
+ );
823
+
824
  // In case automatic inlining is used
825
  $belowSizeInput = (int)Main::instance()->settings['inline_css_files_below_size_input'];
826
 
835
  foreach ($matchesSourcesFromTags as $matchList) {
836
  $matchedTag = $matchList[0];
837
 
838
+ if ($matchedTag === '') {
839
+ continue;
840
+ }
841
+
842
  // They were preloaded for a reason, leave them
843
+ if (strpos($matchedTag, 'data-wpacu-preload-it-async=') !== false || strpos($matchedTag, 'data-wpacu-to-be-preloaded-basic=') !== false) {
 
844
  continue;
845
  }
846
 
849
  }
850
 
851
  // Condition #1: Only chosen (via textarea) CSS get inlined
852
+ $chosenInlineCssMatches = (! empty($allPatterns) && preg_match('/(' . implode('|', $allPatterns) . ')/i', $matchedTag));
 
853
 
854
  // Is auto inline disabled and the chosen CSS does not match? Continue to the next LINK tag
855
  if (! $chosenInlineCssMatches && ! self::isAutoInlineEnabled()) {
889
  // The CSS file is read from its original plugin/theme/cache location
890
  // If minify was enabled, then it's already minified, no point in re-minify it to save resources
891
  // Changing paths (relative) to fonts, images, etc. are relevant in this case
892
+ $cssContent = self::maybeAlterContentForCssFile($cssContent, false);
893
 
894
  if ($cssContent && $cssContent !== '/**/') {
895
  $htmlSource = str_replace(
913
  *
914
  * @param $cssContent
915
  * @param bool $doCssMinify (false by default as it could be already minified or non-minify type)
 
 
916
  * @param array $extraParams
917
  *
918
  * @return mixed|string|string[]|null
919
  */
920
+ public static function maybeAlterContentForCssFile($cssContent, $doCssMinify = false, $extraParams = array())
921
+ {
922
+ if (! trim($cssContent)) {
923
+ return $cssContent;
924
+ }
925
+
926
+ /* [START] Change CSS Content */
927
+ if ( $doCssMinify && in_array('just_minify', $extraParams) ) {
928
+ $cssContent = MinifyCss::applyMinification( $cssContent, $doCssMinify );
929
+ } else {
930
+ // Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
931
+ $cssContent = self::importsUpdate( $cssContent );
932
+
933
+ if ( $doCssMinify ) {
934
+ $cssContent = MinifyCss::applyMinification( $cssContent, $doCssMinify );
935
+ }
936
+
937
+ if ( Main::instance()->settings['google_fonts_remove'] ) {
938
+ $cssContent = FontsGoogleRemove::cleanFontFaceReferences( $cssContent );
939
+ }
940
+
941
+ // Does it have a source map? Strip it
942
+ if (strpos($cssContent, 'sourceMappingURL') !== false) {
943
+ $cssContent = OptimizeCommon::stripSourceMap($cssContent);
944
+ }
945
+ }
946
+ /* [END] Change CSS Content */
947
+
948
+ return $cssContent;
949
+ }
950
+
951
+ /**
952
+ * @param $cssContent
953
+ * @param bool $doCssMinify
954
+ * @param array $extraParams
955
+ *
956
+ * @return mixed|string
957
+ */
958
+ public static function maybeAlterContentForInlineStyleTag($cssContent, $doCssMinify = false, $extraParams = array())
959
  {
960
  if (! trim($cssContent)) {
961
  return $cssContent;
962
  }
963
 
964
+ $useCacheForInlineStyle = true;
965
+
966
+ if (mb_strlen($cssContent) > 500000) { // Bigger then ~500KB? Skip alteration
967
+ return $cssContent;
968
+ }
969
+
970
+ if (mb_strlen($cssContent) < 40000) { // Smaller than than ~40KB? Do not cache it
971
+ $useCacheForInlineStyle = false;
972
+ }
973
+
974
+ // For debugging purposes
975
+ if (isset($_GET['wpacu_no_cache'])) { $useCacheForInlineStyle = false; }
976
+
977
+ if ($useCacheForInlineStyle) {
978
+ // Anything in the cache? Take it from there and don't spend resources with the minification
979
+ // (which in some environments uses the CPU, depending on the complexity of the JavaScript code) and any other alteration
980
+ $cssContentBeforeHash = sha1( $cssContent );
981
+
982
+ $pathToInlineCssOptimizedItem = WP_CONTENT_DIR . self::getRelPathCssCacheDir() . '/item/inline/' . $cssContentBeforeHash . '.css';
983
+
984
+ // Check if the file exists before moving forward
985
+ if ( is_file( $pathToInlineCssOptimizedItem ) ) {
986
+ $cachedCssFileExpiresIn = OptimizeCommon::$cachedAssetFileExpiresIn;
987
+
988
+ if ( filemtime( $pathToInlineCssOptimizedItem ) < ( time() - 1 * $cachedCssFileExpiresIn ) ) {
989
+ // Has the caching period expired? Remove the file as a new one has to be generated
990
+ @unlink( $pathToInlineCssOptimizedItem );
991
+ } else {
992
+ // Not expired / Return its content from the cache in a faster way
993
+ $inlineCssStorageItemJsonContent = trim( FileSystem::file_get_contents( $pathToInlineCssOptimizedItem ) );
994
+
995
+ if ( $inlineCssStorageItemJsonContent !== '' ) {
996
+ return $inlineCssStorageItemJsonContent;
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+
1002
+ /* [START] Change CSS Content */
1003
  if ( $doCssMinify && in_array('just_minify', $extraParams) ) {
1004
+ $cssContent = MinifyCss::applyMinification( $cssContent, $useCacheForInlineStyle );
1005
  } else {
1006
  // Move any @imports to top; This also strips any @imports to Google Fonts if the option is chosen
1007
  $cssContent = self::importsUpdate( $cssContent );
1008
 
1009
  if ( $doCssMinify ) {
1010
+ $cssContent = MinifyCss::applyMinification( $cssContent, $useCacheForInlineStyle );
1011
  }
1012
 
1013
  if ( Main::instance()->settings['google_fonts_remove'] ) {
1014
  $cssContent = FontsGoogleRemove::cleanFontFaceReferences( $cssContent );
1015
  }
1016
  }
1017
+ /* [END] Change CSS Content */
1018
+
1019
+ if ($useCacheForInlineStyle && isset($pathToInlineCssOptimizedItem)) {
1020
+ // Store the optimized content to the cached CSS file which would be read quicker
1021
+ FileSystem::file_put_contents( $pathToInlineCssOptimizedItem, $cssContent );
1022
+ }
1023
 
1024
  return $cssContent;
1025
  }
1247
 
1248
  if (isset($ignoreChild['styles']) && ! empty($ignoreChild['styles'])) {
1249
  foreach (array_keys($ignoreChild['styles']) as $styleHandle) {
1250
+ // Always load the Dashicons if the top admin bar (toolbar) is shown
1251
+ if ($styleHandle === 'dashicons' && is_admin_bar_showing()) {
1252
+ continue;
1253
+ }
1254
+
1255
  if (isset(Main::instance()->wpAllStyles['registered'][$styleHandle]->src, Main::instance()->ignoreChildren['styles'][$styleHandle.'_has_unload_rule']) && Main::instance()->wpAllStyles['registered'][$styleHandle]->src && Main::instance()->ignoreChildren['styles'][$styleHandle.'_has_unload_rule']) {
1256
  if ($scriptExtraAfterHtml = self::generateInlineAssocHtmlForHandle($styleHandle)) {
1257
  $htmlSource = str_replace($scriptExtraAfterHtml, '', $htmlSource);
classes/OptimiseAssets/OptimizeJs.php CHANGED
@@ -6,6 +6,7 @@ use WpAssetCleanUp\CleanUp;
6
  use WpAssetCleanUp\Main;
7
  use WpAssetCleanUp\MetaBoxes;
8
  use WpAssetCleanUp\Misc;
 
9
  use WpAssetCleanUp\Preloads;
10
 
11
  /**
@@ -19,21 +20,20 @@ class OptimizeJs
19
  */
20
  public function init()
21
  {
22
- if (WPACU_GET_LOADED_ASSETS_ACTION === true) {
23
- return;
24
- }
25
-
26
- // Only relevant when the list of CSS/JS is not fetched
27
- add_action( 'wp_print_footer_scripts', array( $this, 'prepareOptimizeList' ), PHP_INT_MAX );
28
  }
29
 
30
  /**
31
  *
32
  */
33
- public function prepareOptimizeList()
34
  {
35
  // Are both Minify and Cache Dynamic JS disabled? No point in continuing and using extra resources as there is nothing to change
36
- if (! self::isWorthCheckingForOptimization()) {
37
  return;
38
  }
39
 
@@ -68,7 +68,9 @@ class OptimizeJs
68
 
69
  // [Start] Collect for caching
70
  foreach ($wpScriptsList as $handle) {
71
- if (! isset($wp_scripts->registered[$handle])) { continue; }
 
 
72
 
73
  $value = $wp_scripts->registered[$handle];
74
 
@@ -78,6 +80,7 @@ class OptimizeJs
78
  }
79
 
80
  $optimizeValues = self::maybeOptimizeIt($value);
 
81
 
82
  if ( ! empty( $optimizeValues ) ) {
83
  $jsOptimizeList[] = $optimizeValues;
@@ -96,6 +99,10 @@ class OptimizeJs
96
  */
97
  public static function maybeOptimizeIt($value)
98
  {
 
 
 
 
99
  global $wp_version;
100
 
101
  $src = isset($value->src) ? $value->src : false;
@@ -112,13 +119,20 @@ class OptimizeJs
112
  $doFileMinify = false;
113
  }
114
 
115
- $fileVer = $dbVer = (isset($value->ver) && $value->ver) ? $value->ver : $wp_version;
116
 
117
  $handleDbStr = md5($value->handle);
118
 
119
  $transientName = 'wpacu_js_optimize_'.$handleDbStr;
120
 
121
- if (Main::instance()->settings['fetch_cached_files_details_from'] === 'db_disk') {
 
 
 
 
 
 
 
122
  if ( ! isset( $GLOBALS['wpacu_from_location_inc'] ) ) {
123
  $GLOBALS['wpacu_from_location_inc'] = 1;
124
  }
@@ -148,11 +162,13 @@ class OptimizeJs
148
  return array(
149
  $savedValuesArray['source_uri'],
150
  $savedValuesArray['optimize_uri'],
151
- $value->src
 
152
  );
153
  }
154
  }
155
  }
 
156
 
157
  // Check if it starts without "/" or a protocol; e.g. "wp-content/theme/script.js"
158
  if (strpos($src, '/') !== 0 &&
@@ -168,6 +184,9 @@ class OptimizeJs
168
  $src = site_url() . $src;
169
  }
170
 
 
 
 
171
  $isJsFile = $jsContentBefore = false;
172
 
173
  if (Main::instance()->settings['cache_dynamic_loaded_js'] &&
@@ -195,43 +214,61 @@ class OptimizeJs
195
  $jsContent = $jsContentBefore = FileSystem::file_get_contents($localAssetPath);
196
  }
197
 
198
- $jsContent = self::maybeAlterJsContent($jsContent, $doFileMinify);
199
 
200
- if ($isJsFile && trim($jsContent, '; ') === trim($jsContentBefore, '; ')) {
201
- // The (static) JS file is already minified / No need to copy it in to the cache (save disk space)
202
- return array();
203
- }
204
 
205
- $jsContent = self::maybeDoJsFixes($jsContent, $pathToAssetDir . '/'); // Minify it and save it to /wp-content/cache/js/min/
 
 
 
206
 
207
- // Relative path to the new file
208
- // Save it to /wp-content/cache/js/{OptimizeCommon::$optimizedSingleFilesDir}/
209
- if ($fileVer !== $wp_version) {
210
- if (is_array($fileVer)) {
211
- // Convert to string if it's an array (rare cases)
212
- $fileVer = implode('-', $fileVer);
213
  }
214
- $fileVer = trim(str_replace(' ', '_', preg_replace('/\s+/', ' ', $fileVer)));
215
- $fileVer = (strlen($fileVer) > 50) ? substr(md5($fileVer), 0, 20) : $fileVer; // don't end up with too long filenames
216
  }
217
 
218
- $newFilePathUri = self::getRelPathJsCacheDir() . OptimizeCommon::$optimizedSingleFilesDir . '/' . $value->handle . '-v' . $fileVer;
219
-
220
- if (isset($localAssetPath)) { // For static files only
221
- $sha1File = @sha1_file($localAssetPath);
222
 
223
- if ($sha1File) {
224
- $newFilePathUri .= '-' . $sha1File;
 
225
  }
 
 
226
  }
 
 
 
 
 
 
 
227
 
 
228
  $newFilePathUri .= '.js';
229
 
 
 
 
 
 
 
 
 
 
230
  $newLocalPath = WP_CONTENT_DIR . $newFilePathUri; // Ful Local path
231
  $newLocalPathUrl = WP_CONTENT_URL . $newFilePathUri; // Full URL path
232
 
233
- if ($jsContent) {
234
- $jsContent = '/*! ' . $sourceBeforeOptimization . ' */' . "\n" . $jsContent;
235
  }
236
 
237
  $saveFile = FileSystem::file_put_contents($newLocalPath, $jsContent);
@@ -253,7 +290,8 @@ class OptimizeJs
253
  return array(
254
  OptimizeCommon::getSourceRelPath($value->src), // Original SRC (Relative path)
255
  OptimizeCommon::getSourceRelPath($newLocalPathUrl), // New SRC (Relative path)
256
- $value->src // SRC (as it is)
 
257
  );
258
  }
259
 
@@ -265,12 +303,13 @@ class OptimizeJs
265
  *
266
  * @return mixed|string|string[]|null
267
  */
268
- public static function maybeAlterJsContent($jsContent, $doJsMinify = false)
269
  {
270
- if (! trim($jsContent)) {
271
  return $jsContent;
272
  }
273
 
 
274
  if ($doJsMinify) {
275
  $jsContent = MinifyJs::applyMinification($jsContent);
276
  }
@@ -281,6 +320,83 @@ class OptimizeJs
281
  // Perhaps "display" parameter has to be applied to Google Font Links if they are active
282
  $jsContent = FontsGoogle::alterGoogleFontUrlFromJsContent($jsContent);
283
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
  return $jsContent;
286
  }
@@ -298,7 +414,9 @@ class OptimizeJs
298
  $cdnUrls = OptimizeCommon::getAnyCdnUrls();
299
  $cdnUrlForJs = isset($cdnUrls['js']) ? $cdnUrls['js'] : false;
300
 
301
- preg_match_all('#(<script[^>]*src(|\s+)=(|\s+)[^>]*(>))|(<link[^>]*(as(\s+|)=(\s+|)(|"|\')script(|"|\'))[^>]*(>))#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
 
 
302
 
303
  foreach ($matchesSourcesFromTags as $matches) {
304
  $scriptSourceTag = $matches[0];
@@ -316,25 +434,33 @@ class OptimizeJs
316
  $forAttr = 'href';
317
  }
318
 
 
 
 
 
 
 
 
319
  // Is it a local JS? Check if it's hardcoded (not enqueued the WordPress way)
320
- if ($cleanScriptSrcFromTagArray = OptimizeCommon::getLocalCleanSourceFromTag($scriptSourceTag, $forAttr)) {
321
- $cleanScriptSrcFromTag = $cleanScriptSrcFromTagArray['source'];
322
- $afterQuestionMark = $cleanScriptSrcFromTagArray['after_question_mark'];
323
-
324
- if (! in_array($cleanScriptSrcFromTag, $allEnqueuedCleanScriptSrcs)) {
325
- // Not in the final enqueued list? Most likely hardcoded (not added via wp_enqueue_scripts())
326
- // Emulate the object value (as the enqueued styles)
327
- $value = (object)array(
328
- 'handle' => md5($cleanScriptSrcFromTag),
329
- 'src' => $cleanScriptSrcFromTag,
330
- 'ver' => md5($afterQuestionMark)
331
- );
332
-
333
- $optimizeValues = self::maybeOptimizeIt($value);
334
-
335
- if (! empty($optimizeValues)) {
336
- $jsOptimizeList[] = $optimizeValues;
337
- }
 
338
  }
339
  }
340
 
@@ -342,14 +468,16 @@ class OptimizeJs
342
  continue;
343
  }
344
 
345
- foreach ($jsOptimizeList as $listValues) {
346
  // Index 0: Source URL (relative)
347
  // Index 1: New Optimized URL (relative)
348
  // Index 2: Source URL (as it is)
349
 
350
  // If the minified files are deleted (e.g. /wp-content/cache/ is cleared)
351
  // do not replace the JS file path to avoid breaking the website
352
- if (! is_file(rtrim(ABSPATH, '/') . $listValues[1])) {
 
 
353
  continue;
354
  }
355
 
@@ -380,13 +508,36 @@ class OptimizeJs
380
  $optimizeUrl = OptimizeCommon::cdnToUrlFormat($cdnUrlForJs, 'raw') . $listValues[1]; // string
381
 
382
  if ($scriptSourceTag !== str_ireplace($sourceUrlList, $optimizeUrl, $scriptSourceTag)) {
383
- $newLinkSourceTag = self::updateOriginalToOptimizedTag($scriptSourceTag, $sourceUrlList, $optimizeUrl);
384
- $htmlSource = str_replace($scriptSourceTag, $newLinkSourceTag, $htmlSource);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  break;
386
  }
387
  }
388
  }
389
 
 
 
390
  return $htmlSource;
391
  }
392
 
@@ -478,6 +629,9 @@ class OptimizeJs
478
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
479
  }
480
 
 
 
 
481
  $proceedWithCombineOnThisPage = true;
482
 
483
  // If "Do not combine JS on this page" is checked in "Asset CleanUp Options" side meta box
@@ -495,110 +649,24 @@ class OptimizeJs
495
  /* [wpacu_timing] */ // Note: Load timing is checked within the method /* [/wpacu_timing] */
496
  $htmlSource = CombineJs::doCombine($htmlSource);
497
  }
 
498
 
499
- if (self::isWorthCheckingForOptimization() && ! Main::instance()->preventAssetsSettings()) {
500
  /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_minify_inline_script_tags'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
501
- $htmlSource = self::minifyInlineScriptTags($htmlSource);
502
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
503
  }
504
 
505
  // Final cleanups
506
- $htmlSource = preg_replace('#(\s+|)(data-wpacu-jquery-core-handle=1|data-wpacu-jquery-migrate-handle=1)(\s+|)#Umi', '', $htmlSource);
507
 
508
- $htmlSource = preg_replace('#(\s+|)data-wpacu-script-rel-src-before=(["\'])' . '(.*)' . '(\1)(\s+|)#Usmi', '', $htmlSource);
509
  $htmlSource = preg_replace('#<script(.*)data-wpacu-script-handle=\'(.*)\'#Umi', '<script \\1', $htmlSource);
510
 
511
  // Clear possible empty SCRIPT tags (e.g. left from associated 'before' and 'after' tags after their content was stripped)
512
  $htmlSource = preg_replace('#<script(\s+| )(type=\'text/javascript\'|)(\s+|)></script>#Umi', '', $htmlSource);
513
 
514
  /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_optimize_js', 'end'); /* [/wpacu_timing] */
515
-
516
- return $htmlSource;
517
- }
518
-
519
- /**
520
- * @param $htmlSource
521
- *
522
- * @return mixed|string
523
- */
524
- public static function minifyInlineScriptTags($htmlSource)
525
- {
526
- if (stripos($htmlSource, '<script') === false) {
527
- return $htmlSource; // no SCRIPT tags, hmm
528
- }
529
-
530
- // DOMDocument extension has to be enabled, otherwise return the HTML source as was (no changes)
531
- if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('DOMDocument'))) {
532
- return $htmlSource;
533
- }
534
-
535
- $domTag = new \DOMDocument();
536
- libxml_use_internal_errors(true);
537
- $domTag->loadHTML($htmlSource);
538
-
539
- $scriptTagsObj = $domTag->getElementsByTagName( 'script' );
540
-
541
- if ($scriptTagsObj === null) {
542
- return $htmlSource;
543
- }
544
-
545
- $doJsMinifyInline = MinifyJs::isMinifyJsEnabled() && Main::instance()->settings['minify_loaded_js_inline'];
546
-
547
- $skipTagsContaining = array_map( static function ( $toMatch ) {
548
- return preg_quote($toMatch, '/');
549
- }, array(
550
- '/* <![CDATA[ */', // added via wp_localize_script()
551
- 'window._wpemojiSettings', // Emoji
552
- 'wpacu-google-fonts-async-load',
553
- 'wpacu-preload-async-css-fallback',
554
- /* [wpacu_pro] */'data-wpacu-inline-js-file',/* [/wpacu_pro] */
555
- 'document.body.prepend(wpacuLinkTag',
556
- 'var wc_product_block_data = JSON.parse( decodeURIComponent(',
557
- '/(^|\s)(no-)?customize-support(?=\s|$)/', // WP Core
558
- 'b[c] += ( window.postMessage && request ? \' \' : \' no-\' ) + cs;', // WP Core
559
- 'data-wpacu-own-inline-script' // Only shown to the admin, irrelevant for any optimization (save resources)
560
- ));
561
-
562
- foreach ($scriptTagsObj as $scriptTagObj) {
563
- // Does it have the "src" attribute? Skip it as it's not an inline SCRIPT tag
564
- if (isset($scriptTagObj->attributes) && $scriptTagObj->attributes !== null) {
565
- foreach ($scriptTagObj->attributes as $attrObj) {
566
- if ($attrObj->nodeName === 'src') {
567
- continue 2;
568
- }
569
-
570
- if ($attrObj->nodeName === 'type' && $attrObj->nodeValue !== 'text/javascript') {
571
- // If a "type" parameter exists (otherwise it defaults to "text/javascript"
572
- // and the value of "type" is not "text/javascript", do not proceed with any optimization (including minification)
573
- continue 2;
574
- }
575
- }
576
- }
577
-
578
- $originalTag = CleanUp::getOuterHTML($scriptTagObj);
579
-
580
- // No need to use extra resources as the tag is already minified
581
- if (preg_match('/('.implode('|', $skipTagsContaining).')/', $originalTag)) {
582
- continue;
583
- }
584
-
585
- $originalTagContents = (isset($scriptTagObj->nodeValue) && trim($scriptTagObj->nodeValue) !== '') ? $scriptTagObj->nodeValue : false;
586
-
587
- if ($originalTagContents) {
588
- $newTagContents = self::maybeAlterJsContent($originalTagContents, $doJsMinifyInline);
589
-
590
- if ($newTagContents !== $originalTagContents) {
591
- $htmlSource = str_ireplace(
592
- '>' . $originalTagContents . '</script',
593
- '>' . $newTagContents . '</script',
594
- $htmlSource
595
- );
596
- }
597
-
598
- libxml_clear_errors();
599
- }
600
- }
601
-
602
  return $htmlSource;
603
  }
604
 
@@ -700,13 +768,11 @@ class OptimizeJs
700
  return $htmlSource; // no SCRIPT tags, hmm
701
  }
702
 
703
- if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('DOMDocument')) && class_exists('DOMXpath')) {
704
  return $htmlSource; // DOMDocument has to be enabled
705
  }
706
 
707
- $domTag = new \DOMDocument();
708
- libxml_use_internal_errors(true);
709
- $domTag->loadHTML($htmlSource);
710
 
711
  $scriptTagsObj = $domTag->getElementsByTagName( 'script' );
712
 
@@ -1037,6 +1103,10 @@ class OptimizeJs
1037
  if ( $type === 'data' ) {
1038
  if ( $inlineScriptContent === '' ) {
1039
  $inlineScriptContent = $wp_scripts->get_data( $handle, 'data' );
 
 
 
 
1040
  }
1041
 
1042
  $output .= "<script{$typeAttr}>\n";
@@ -1058,10 +1128,14 @@ class OptimizeJs
1058
  if ( $type === 'before' || $type === 'after' ) {
1059
  if ( $inlineScriptContent === '' ) {
1060
  $inlineScriptContent = $wp_scripts->print_inline_script( $handle, $type, false );
 
 
 
 
1061
  }
1062
 
1063
  if ( $inlineScriptContent ) {
1064
- $output = sprintf( "<script%s>\n%s\n</script>", $typeAttr, $inlineScriptContent );
1065
  }
1066
  }
1067
 
6
  use WpAssetCleanUp\Main;
7
  use WpAssetCleanUp\MetaBoxes;
8
  use WpAssetCleanUp\Misc;
9
+ use WpAssetCleanUp\Plugin;
10
  use WpAssetCleanUp\Preloads;
11
 
12
  /**
20
  */
21
  public function init()
22
  {
23
+ add_action( 'wp_print_footer_scripts', static function() {
24
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'prepare_optimize_files_js' ); /* [/wpacu_timing] */
25
+ self::prepareOptimizeList();
26
+ /* [wpacu_timing] */ Misc::scriptExecTimer( 'prepare_optimize_files_js', 'end' ); /* [/wpacu_timing] */
27
+ }, PHP_INT_MAX );
 
28
  }
29
 
30
  /**
31
  *
32
  */
33
+ public static function prepareOptimizeList()
34
  {
35
  // Are both Minify and Cache Dynamic JS disabled? No point in continuing and using extra resources as there is nothing to change
36
+ if ( ! self::isWorthCheckingForOptimization() || Plugin::preventAnyChanges() ) {
37
  return;
38
  }
39
 
68
 
69
  // [Start] Collect for caching
70
  foreach ($wpScriptsList as $handle) {
71
+ if (! isset($wp_scripts->registered[$handle]->src)) {
72
+ continue;
73
+ }
74
 
75
  $value = $wp_scripts->registered[$handle];
76
 
80
  }
81
 
82
  $optimizeValues = self::maybeOptimizeIt($value);
83
+ wp_cache_set('wpacu_maybe_optimize_it_js_'.$handle, $optimizeValues);
84
 
85
  if ( ! empty( $optimizeValues ) ) {
86
  $jsOptimizeList[] = $optimizeValues;
99
  */
100
  public static function maybeOptimizeIt($value)
101
  {
102
+ if ($optimizeValues = wp_cache_get('wpacu_maybe_optimize_it_js_'.$value->handle)) {
103
+ return $optimizeValues;
104
+ }
105
+
106
  global $wp_version;
107
 
108
  $src = isset($value->src) ? $value->src : false;
119
  $doFileMinify = false;
120
  }
121
 
122
+ $dbVer = (isset($value->ver) && $value->ver) ? $value->ver : $wp_version;
123
 
124
  $handleDbStr = md5($value->handle);
125
 
126
  $transientName = 'wpacu_js_optimize_'.$handleDbStr;
127
 
128
+ $skipCache = false;
129
+
130
+ if (isset($_GET['wpacu_no_cache'])) {
131
+ $skipCache = true;
132
+ }
133
+
134
+ if (! $skipCache) {
135
+ if (Main::instance()->settings['fetch_cached_files_details_from'] === 'db_disk') {
136
  if ( ! isset( $GLOBALS['wpacu_from_location_inc'] ) ) {
137
  $GLOBALS['wpacu_from_location_inc'] = 1;
138
  }
162
  return array(
163
  $savedValuesArray['source_uri'],
164
  $savedValuesArray['optimize_uri'],
165
+ $value->src,
166
+ $value->handle
167
  );
168
  }
169
  }
170
  }
171
+ }
172
 
173
  // Check if it starts without "/" or a protocol; e.g. "wp-content/theme/script.js"
174
  if (strpos($src, '/') !== 0 &&
184
  $src = site_url() . $src;
185
  }
186
 
187
+ /*
188
+ * [START] JS Content Optimization
189
+ */
190
  $isJsFile = $jsContentBefore = false;
191
 
192
  if (Main::instance()->settings['cache_dynamic_loaded_js'] &&
214
  $jsContent = $jsContentBefore = FileSystem::file_get_contents($localAssetPath);
215
  }
216
 
217
+ $jsContent = trim($jsContent);
218
 
219
+ // If it stays like this, it means there is content there, even if only comments
220
+ $jsContentBecomesEmptyAfterMin = false;
 
 
221
 
222
+ if ($doFileMinify && $jsContent) { // only bother to minify it if it has any content, save resources
223
+ // Minify this file?
224
+ $jsContentBeforeMin = $jsContent;
225
+ $jsContentAfterMin = MinifyJs::applyMinification($jsContentBeforeMin);
226
 
227
+ $jsContent = $jsContentAfterMin;
228
+
229
+ if ($jsContentBeforeMin && $jsContentAfterMin === '') {
230
+ // It had content, but became empty after minification, most likely it had only comments (e.g. a default child theme's style)
231
+ $jsContentBecomesEmptyAfterMin = true;
 
232
  }
 
 
233
  }
234
 
235
+ if ($jsContentBecomesEmptyAfterMin || $jsContent === '') {
236
+ $jsContent = '/**/';
237
+ } else {
238
+ $jsContent = self::maybeAlterContentForJsFile( $jsContent, false );
239
 
240
+ if ( $isJsFile && trim( $jsContent, '; ' ) === trim( $jsContentBefore, '; ' ) ) {
241
+ // The (static) JS file is already minified / No need to copy it in to the cache (save disk space)
242
+ return array();
243
  }
244
+
245
+ $jsContent = self::maybeDoJsFixes( $jsContent, $pathToAssetDir . '/' ); // Minify it and save it to /wp-content/cache/js/min/
246
  }
247
+ /*
248
+ * [END] JS Content Optimization
249
+ */
250
+
251
+ // Relative path to the new file
252
+ // Save it to /wp-content/cache/js/{OptimizeCommon::$optimizedSingleFilesDir}/
253
+ $fileVer = sha1($jsContent);
254
 
255
+ $newFilePathUri = self::getRelPathJsCacheDir() . OptimizeCommon::$optimizedSingleFilesDir . '/' . $value->handle . '-v' . $fileVer;
256
  $newFilePathUri .= '.js';
257
 
258
+ if ($jsContent === '') {
259
+ $jsContent = '/**/';
260
+ }
261
+
262
+ if ($jsContent === '/**/') {
263
+ // Leave a signature that the file is empty, thus it would be faster to take further actions upon it later on, saving resources)
264
+ $newFilePathUri = str_replace('.js', '-wpacu-empty-file.js', $newFilePathUri);
265
+ }
266
+
267
  $newLocalPath = WP_CONTENT_DIR . $newFilePathUri; // Ful Local path
268
  $newLocalPathUrl = WP_CONTENT_URL . $newFilePathUri; // Full URL path
269
 
270
+ if ($jsContent && $jsContent !== '/**/') {
271
+ $jsContent = '/*!' . $sourceBeforeOptimization . '*/' . "\n" . $jsContent;
272
  }
273
 
274
  $saveFile = FileSystem::file_put_contents($newLocalPath, $jsContent);
290
  return array(
291
  OptimizeCommon::getSourceRelPath($value->src), // Original SRC (Relative path)
292
  OptimizeCommon::getSourceRelPath($newLocalPathUrl), // New SRC (Relative path)
293
+ $value->src, // SRC (as it is)
294
+ $value->handle
295
  );
296
  }
297
 
303
  *
304
  * @return mixed|string|string[]|null
305
  */
306
+ public static function maybeAlterContentForJsFile($jsContent, $doJsMinify = false)
307
  {
308
+ if (! trim($jsContent)) { // No Content! Return it as it, no point in doing extra checks
309
  return $jsContent;
310
  }
311
 
312
+ /* [START] Change JS Content */
313
  if ($doJsMinify) {
314
  $jsContent = MinifyJs::applyMinification($jsContent);
315
  }
320
  // Perhaps "display" parameter has to be applied to Google Font Links if they are active
321
  $jsContent = FontsGoogle::alterGoogleFontUrlFromJsContent($jsContent);
322
  }
323
+ /* [END] Change JS Content */
324
+
325
+ // Does it have a source map? Strip it
326
+ if (strpos($jsContent, 'sourceMappingURL') !== false) {
327
+ $jsContent = OptimizeCommon::stripSourceMap($jsContent);
328
+ }
329
+
330
+ return $jsContent;
331
+ }
332
+
333
+ /**
334
+ * @param $jsContent
335
+ * @param $doJsMinify
336
+ *
337
+ * @return false|mixed|string|string[]|null
338
+ */
339
+ public static function maybeAlterContentForInlineScriptTag($jsContent, $doJsMinify)
340
+ {
341
+ if (! trim($jsContent)) { // No Content! Return it as it, no point in doing extra checks
342
+ return $jsContent;
343
+ }
344
+
345
+ if (mb_strlen($jsContent) > 500000) { // Bigger then ~500KB? Skip alteration for this inline SCRIPT
346
+ return $jsContent;
347
+ }
348
+
349
+ $useCacheForInlineScript = true;
350
+
351
+ if (mb_strlen($jsContent) < 40000) { // Smaller than ~40KB? Do not cache it
352
+ $useCacheForInlineScript = false;
353
+ }
354
+
355
+ // For debugging purposes
356
+ if (isset($_GET['wpacu_no_cache'])) { $useCacheForInlineScript = false; }
357
+
358
+ if ($useCacheForInlineScript) {
359
+ // Anything in the cache? Take it from there and don't spend resources with the minification
360
+ // (which in some environments uses the CPU, depending on the complexity of the JavaScript code) and any other alteration
361
+ $jsContentBeforeHash = sha1( $jsContent );
362
+
363
+ $pathToInlineJsOptimizedItem = WP_CONTENT_DIR . self::getRelPathJsCacheDir() . '/item/inline/' . $jsContentBeforeHash . '.js';
364
+
365
+ // Check if the file exists before moving forward
366
+ if ( is_file( $pathToInlineJsOptimizedItem ) ) {
367
+ $cachedJsFileExpiresIn = OptimizeCommon::$cachedAssetFileExpiresIn;
368
+
369
+ if ( filemtime( $pathToInlineJsOptimizedItem ) < ( time() - 1 * $cachedJsFileExpiresIn ) ) {
370
+ // Has the caching period expired? Remove the file as a new one has to be generated
371
+ @unlink( $pathToInlineJsOptimizedItem );
372
+ } else {
373
+ // Not expired / Return its content from the cache in a faster way
374
+ $inlineJsStorageItemJsonContent = FileSystem::file_get_contents( $pathToInlineJsOptimizedItem );
375
+
376
+ if ( $inlineJsStorageItemJsonContent !== '' ) {
377
+ return $inlineJsStorageItemJsonContent;
378
+ }
379
+ }
380
+ }
381
+ }
382
+
383
+ /* [START] Change JS Content */
384
+ if ($doJsMinify) {
385
+ $jsContent = MinifyJs::applyMinification($jsContent);
386
+ }
387
+
388
+ if (Main::instance()->settings['google_fonts_remove']) {
389
+ $jsContent = FontsGoogleRemove::stripReferencesFromJsCode($jsContent);
390
+ } elseif (Main::instance()->settings['google_fonts_display']) {
391
+ // Perhaps "display" parameter has to be applied to Google Font Links if they are active
392
+ $jsContent = FontsGoogle::alterGoogleFontUrlFromJsContent($jsContent);
393
+ }
394
+ /* [END] Change JS Content */
395
+
396
+ if ( $useCacheForInlineScript && isset($pathToInlineJsOptimizedItem)) {
397
+ // Store the optimized content to the cached JS file which would be read quicker
398
+ FileSystem::file_put_contents( $pathToInlineJsOptimizedItem, $jsContent );
399
+ }
400
 
401
  return $jsContent;
402
  }
414
  $cdnUrls = OptimizeCommon::getAnyCdnUrls();
415
  $cdnUrlForJs = isset($cdnUrls['js']) ? $cdnUrls['js'] : false;
416
 
417
+ preg_match_all('#(<script[^>]*src(|\s+)=(|\s+)[^>]*>)|(<link[^>]*(as(\s+|)=(\s+|)(|"|\')script(|"|\'))[^>]*>)#Umi', $htmlSource, $matchesSourcesFromTags, PREG_SET_ORDER);
418
+
419
+ $scriptTagsToUpdate = array();
420
 
421
  foreach ($matchesSourcesFromTags as $matches) {
422
  $scriptSourceTag = $matches[0];
434
  $forAttr = 'href';
435
  }
436
 
437
+ $cleanScriptSrcFromTagArray = OptimizeCommon::getLocalCleanSourceFromTag($scriptSourceTag, $forAttr);
438
+
439
+ // Skip external links, no point in carrying on
440
+ if (! $cleanScriptSrcFromTagArray || ! is_array($cleanScriptSrcFromTagArray)) {
441
+ continue;
442
+ }
443
+
444
  // Is it a local JS? Check if it's hardcoded (not enqueued the WordPress way)
445
+ $cleanScriptSrcFromTag = $cleanScriptSrcFromTagArray['source'];
446
+ $afterQuestionMark = $cleanScriptSrcFromTagArray['after_question_mark'];
447
+
448
+ if (! in_array($cleanScriptSrcFromTag, $allEnqueuedCleanScriptSrcs)) {
449
+ // Not in the final enqueued list? Most likely hardcoded (not added via wp_enqueue_scripts())
450
+ // Emulate the object value (as the enqueued styles)
451
+ $generatedHandle = md5($cleanScriptSrcFromTag);
452
+
453
+ $value = (object)array(
454
+ 'handle' => $generatedHandle,
455
+ 'src' => $cleanScriptSrcFromTag,
456
+ 'ver' => md5($afterQuestionMark)
457
+ );
458
+
459
+ $optimizeValues = self::maybeOptimizeIt($value);
460
+ wp_cache_set('wpacu_maybe_optimize_it_js_'.$generatedHandle, $optimizeValues);
461
+
462
+ if (! empty($optimizeValues)) {
463
+ $jsOptimizeList[] = $optimizeValues;
464
  }
465
  }
466
 
468
  continue;
469
  }
470
 
471
+ foreach ($jsOptimizeList as $jsItemIndex => $listValues) {
472
  // Index 0: Source URL (relative)
473
  // Index 1: New Optimized URL (relative)
474
  // Index 2: Source URL (as it is)
475
 
476
  // If the minified files are deleted (e.g. /wp-content/cache/ is cleared)
477
  // do not replace the JS file path to avoid breaking the website
478
+ $localPathOptimizedFile = rtrim(ABSPATH, '/') . $listValues[1];
479
+
480
+ if (! is_file($localPathOptimizedFile)) {
481
  continue;
482
  }
483
 
508
  $optimizeUrl = OptimizeCommon::cdnToUrlFormat($cdnUrlForJs, 'raw') . $listValues[1]; // string
509
 
510
  if ($scriptSourceTag !== str_ireplace($sourceUrlList, $optimizeUrl, $scriptSourceTag)) {
511
+ // Extra measure: Check the file size which should be 4 bytes, but add some margin error in case some environments will report less
512
+ $isEmptyOptimizedFile = (strpos($localPathOptimizedFile, '-wpacu-empty-file.js') !== false && filesize($localPathOptimizedFile) < 10);
513
+
514
+ if ($isEmptyOptimizedFile) {
515
+ // Strip it as its content (after optimization, for instance) is empty; no point in having extra HTTP requests
516
+ $scriptTagsToUpdate[$scriptSourceTag.'</script>'] = '';
517
+
518
+ // Any SCRIPT inline associated with the tag? Strip it
519
+ foreach (array('data', 'before', 'after') as $inlineType) {
520
+ if ( $scriptExtraAfterHtml = self::generateInlineAssocHtmlForHandle( $listValues[3], $inlineType ) ) {
521
+ if (strlen($scriptExtraAfterHtml) < 200) { // strtr() does better with smaller keys
522
+ $scriptTagsToUpdate[ $scriptExtraAfterHtml ] = '';
523
+ } else {
524
+ $htmlSource = str_replace( $scriptExtraAfterHtml, '', $htmlSource );
525
+ }
526
+ }
527
+ }
528
+ } else {
529
+ $newScriptSourceTag = self::updateOriginalToOptimizedTag( $scriptSourceTag, $sourceUrlList, $optimizeUrl );
530
+ $scriptTagsToUpdate[$scriptSourceTag] = $newScriptSourceTag;
531
+ }
532
+
533
+ unset($jsOptimizeList[$jsItemIndex]); // item from the array is not needed anymore
534
  break;
535
  }
536
  }
537
  }
538
 
539
+ $htmlSource = strtr($htmlSource, $scriptTagsToUpdate);
540
+
541
  return $htmlSource;
542
  }
543
 
629
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
630
  }
631
 
632
+ /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_combine_js';
633
+
634
+ Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
635
  $proceedWithCombineOnThisPage = true;
636
 
637
  // If "Do not combine JS on this page" is checked in "Asset CleanUp Options" side meta box
649
  /* [wpacu_timing] */ // Note: Load timing is checked within the method /* [/wpacu_timing] */
650
  $htmlSource = CombineJs::doCombine($htmlSource);
651
  }
652
+ /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
653
 
654
+ if (self::isWorthCheckingForOptimization() && ! Main::instance()->preventAssetsSettings() && (MinifyJs::isMinifyJsEnabled() && Main::instance()->settings['minify_loaded_js_inline'])) {
655
  /* [wpacu_timing] */ $wpacuTimingName = 'alter_html_source_for_minify_inline_script_tags'; Misc::scriptExecTimer($wpacuTimingName); /* [/wpacu_timing] */
656
+ $htmlSource = MinifyJs::minifyInlineScriptTags($htmlSource);
657
  /* [wpacu_timing] */ Misc::scriptExecTimer($wpacuTimingName, 'end'); /* [/wpacu_timing] */
658
  }
659
 
660
  // Final cleanups
661
+ $htmlSource = preg_replace('#(\s+|)(data-wpacu-jquery-core-handle=1|data-wpacu-jquery-migrate-handle=1)(\s+|)#Umi', ' ', $htmlSource);
662
 
663
+ $htmlSource = preg_replace('#(\s+|)data-wpacu-script-rel-src-before=(["\'])' . '(.*)' . '(\1)(\s+|)#Usmi', ' ', $htmlSource);
664
  $htmlSource = preg_replace('#<script(.*)data-wpacu-script-handle=\'(.*)\'#Umi', '<script \\1', $htmlSource);
665
 
666
  // Clear possible empty SCRIPT tags (e.g. left from associated 'before' and 'after' tags after their content was stripped)
667
  $htmlSource = preg_replace('#<script(\s+| )(type=\'text/javascript\'|)(\s+|)></script>#Umi', '', $htmlSource);
668
 
669
  /* [wpacu_timing] */ Misc::scriptExecTimer('alter_html_source_for_optimize_js', 'end'); /* [/wpacu_timing] */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
670
  return $htmlSource;
671
  }
672
 
768
  return $htmlSource; // no SCRIPT tags, hmm
769
  }
770
 
771
+ if (! (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument')) && class_exists('\DOMXpath')) {
772
  return $htmlSource; // DOMDocument has to be enabled
773
  }
774
 
775
+ $domTag = OptimizeCommon::getDomLoadedTag($htmlSource, 'moveInlinejQueryAfterjQuerySrc');
 
 
776
 
777
  $scriptTagsObj = $domTag->getElementsByTagName( 'script' );
778
 
1103
  if ( $type === 'data' ) {
1104
  if ( $inlineScriptContent === '' ) {
1105
  $inlineScriptContent = $wp_scripts->get_data( $handle, 'data' );
1106
+
1107
+ if (! $inlineScriptContent) {
1108
+ return '';
1109
+ }
1110
  }
1111
 
1112
  $output .= "<script{$typeAttr}>\n";
1128
  if ( $type === 'before' || $type === 'after' ) {
1129
  if ( $inlineScriptContent === '' ) {
1130
  $inlineScriptContent = $wp_scripts->print_inline_script( $handle, $type, false );
1131
+
1132
+ if (! $inlineScriptContent) {
1133
+ return '';
1134
+ }
1135
  }
1136
 
1137
  if ( $inlineScriptContent ) {
1138
+ $output = sprintf( "<script%s>\n%s\n</script>\n", $typeAttr, $inlineScriptContent );
1139
  }
1140
  }
1141
 
classes/OwnAssets.php CHANGED
@@ -43,6 +43,13 @@ class OwnAssets
43
  $wpacu_object_data['source_load_error_msg'] = __('It looks like the source is not reachable', 'wp-asset-clean-up');
44
  $wpacu_object_data['plugin_id'] = WPACU_PLUGIN_ID;
45
  $wpacu_object_data['ajax_url'] = admin_url('admin-ajax.php');
 
 
 
 
 
 
 
46
 
47
  $wpacu_object_data['jquery_unload_alert'] = 'jQuery library is a WordPress library that it is used in WordPress plugins/themes most of the time.'."\n\n".
48
  'There are currently other JavaScript "children" files connected to it, that will stop working, if this library is unloaded'."\n\n".
@@ -95,6 +102,12 @@ class OwnAssets
95
  * [End] Trigger ONLY other plugins'/system caches
96
  */
97
 
 
 
 
 
 
 
98
  return $wpacu_object_data;
99
  });
100
  }
@@ -362,48 +375,38 @@ HTML;
362
  </div>
363
  HTML;
364
 
365
- $wpacuObjectData['jquery_migration_disable_confirm_msg'] =
366
- __('Make sure to properly test your website if you unload the jQuery migration library.',
367
- 'wp-asset-clean-up') . "\n\n" .
368
- __('In some cases, due to old jQuery code triggered from plugins or the theme, unloading this migration library could cause those scripts not to function anymore and break some of the front-end functionality.',
369
- 'wp-asset-clean-up') . "\n\n" .
370
- __('If you are not sure about whether activating this option is right or not, it is better to leave it as it is (to be loaded by default) and consult with a developer.',
371
- 'wp-asset-clean-up') . "\n\n" .
372
- __('Confirm this action to enable the unloading or cancel to leave it loaded by default.',
373
- 'wp-asset-clean-up');
374
-
375
- $wpacuObjectData['comment_reply_disable_confirm_msg'] =
376
- __('This is worth disabling if you are NOT using the default WordPress comment system (e.g. you are using the website for business purposes, to showcase your products and you are not using it as a blog where people leave comments to your posts).',
377
- 'wp-asset-clean-up') . "\n\n" .
378
- __('If you are not sure about whether activating this option is right or not, it is better to leave it as it is (to be loaded by default).',
379
- 'wp-asset-clean-up') . "\n\n" .
380
- __('Confirm this action to enable the unloading or cancel to leave it loaded by default.',
381
- 'wp-asset-clean-up');
382
-
383
- // "Tools" - "Reset"
384
- $wpacuObjectData['reset_settings_confirm_msg'] =
385
- __('Are you sure you want to reset the settings to their default values?', 'wp-asset-clean-up') . "\n\n" .
386
- __('This is an irreversible action.', 'wp-asset-clean-up') . "\n\n" .
387
- __('Please confirm to continue or "Cancel" to abort it', 'wp-asset-clean-up');
388
-
389
- $wpacuObjectData['reset_everything_except_settings_confirm_msg'] =
390
- __('Are you sure you want to reset everything (unloads, load exceptions etc.) except settings?',
391
- 'wp-asset-clean-up') . "\n\n" .
392
- __('This is an irreversible action.', 'wp-asset-clean-up') . "\n\n" .
393
- __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
394
-
395
- $wpacuObjectData['reset_everything_confirm_msg'] =
396
- __('Are you sure you want to reset everything (settings, unloads, load exceptions etc.) to the same point it was when you first activated the plugin?',
397
- 'wp-asset-clean-up') . "\n\n" .
398
- __('This is an irreversible action.', 'wp-asset-clean-up') . "\n\n" .
399
- __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
400
-
401
- // "Tools" - "Import & Export"
402
- $wpacuObjectData['import_confirm_msg'] =
403
- __('This process is NOT reversible.', 'wp-asset-clean-up') . "\n\n" .
404
- __('Please make sure you have a backup (e.g. an exported JSON file) before proceeding.',
405
- 'wp-asset-clean-up') . "\n\n" .
406
- __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
407
 
408
  wp_localize_script(
409
  WPACU_PLUGIN_ID . '-script',
43
  $wpacu_object_data['source_load_error_msg'] = __('It looks like the source is not reachable', 'wp-asset-clean-up');
44
  $wpacu_object_data['plugin_id'] = WPACU_PLUGIN_ID;
45
  $wpacu_object_data['ajax_url'] = admin_url('admin-ajax.php');
46
+ $wpacu_object_data['is_frontend_view'] = false;
47
+
48
+ // Current Page URL (for preloading) in the front-end view
49
+ if (! is_admin()) {
50
+ $wpacu_object_data['page_url'] = Misc::getCurrentPageUrl();
51
+ $wpacu_object_data['is_frontend_view'] = true;
52
+ }
53
 
54
  $wpacu_object_data['jquery_unload_alert'] = 'jQuery library is a WordPress library that it is used in WordPress plugins/themes most of the time.'."\n\n".
55
  'There are currently other JavaScript "children" files connected to it, that will stop working, if this library is unloaded'."\n\n".
102
  * [End] Trigger ONLY other plugins'/system caches
103
  */
104
 
105
+ $wpacu_object_data['server_returned_404_not_found'] = sprintf(
106
+ __('When accessing this page the server responded with a status of %s404 (Not Found)%s. If this page is meant to return this status, you can ignore this message, otherwise you might have a problem with this page if it is meant to return a standard 200 OK status.', 'wp-asset-clean-up'),
107
+ '<strong>',
108
+ '</strong>'
109
+ );
110
+
111
  return $wpacu_object_data;
112
  });
113
  }
375
  </div>
376
  HTML;
377
 
378
+ $wpacuObjectData['jquery_migration_disable_confirm_msg'] =
379
+ __('Make sure to properly test your website if you unload the jQuery migration library.', 'wp-asset-clean-up')."\n\n".
380
+ __('In some cases, due to old jQuery code triggered from plugins or the theme, unloading this migration library could cause those scripts not to function anymore and break some of the front-end functionality.', 'wp-asset-clean-up')."\n\n".
381
+ __('If you are not sure about whether activating this option is right or not, it is better to leave it as it is (to be loaded by default) and consult with a developer.', 'wp-asset-clean-up')."\n\n".
382
+ __('Confirm this action to enable the unloading or cancel to leave it loaded by default.', 'wp-asset-clean-up');
383
+
384
+ $wpacuObjectData['comment_reply_disable_confirm_msg'] =
385
+ __('This is worth disabling if you are NOT using the default WordPress comment system (e.g. you are using the website for business purposes, to showcase your products and you are not using it as a blog where people leave comments to your posts).', 'wp-asset-clean-up')."\n\n".
386
+ __('If you are not sure about whether activating this option is right or not, it is better to leave it as it is (to be loaded by default).', 'wp-asset-clean-up')."\n\n".
387
+ __('Confirm this action to enable the unloading or cancel to leave it loaded by default.', 'wp-asset-clean-up');
388
+
389
+ // "Tools" - "Reset"
390
+ $wpacuObjectData['reset_settings_confirm_msg'] =
391
+ __('Are you sure you want to reset the settings to their default values?', 'wp-asset-clean-up')."\n\n".
392
+ __('This is an irreversible action.', 'wp-asset-clean-up')."\n\n".
393
+ __('Please confirm to continue or "Cancel" to abort it', 'wp-asset-clean-up');
394
+
395
+ $wpacuObjectData['reset_everything_except_settings_confirm_msg'] =
396
+ __('Are you sure you want to reset everything (unloads, load exceptions etc.) except settings?', 'wp-asset-clean-up')."\n\n".
397
+ __('This is an irreversible action.', 'wp-asset-clean-up')."\n\n".
398
+ __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
399
+
400
+ $wpacuObjectData['reset_everything_confirm_msg'] =
401
+ __('Are you sure you want to reset everything (settings, unloads, load exceptions etc.) to the same point it was when you first activated the plugin?', 'wp-asset-clean-up')."\n\n".
402
+ __('This is an irreversible action.', 'wp-asset-clean-up')."\n\n".
403
+ __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
404
+
405
+ // "Tools" - "Import & Export"
406
+ $wpacuObjectData['import_confirm_msg'] =
407
+ __('This process is NOT reversible.', 'wp-asset-clean-up')."\n\n".
408
+ __('Please make sure you have a backup (e.g. an exported JSON file) before proceeding.', 'wp-asset-clean-up')."\n\n".
409
+ __('Please confirm to continue or "Cancel" to abort it.', 'wp-asset-clean-up');
 
 
 
 
 
 
 
 
 
 
410
 
411
  wp_localize_script(
412
  WPACU_PLUGIN_ID . '-script',
classes/Plugin.php CHANGED
@@ -17,8 +17,6 @@ class Plugin
17
  const RATE_URL = 'https://wordpress.org/support/plugin/wp-asset-clean-up/reviews/?filter=5#new-post';
18
 
19
  /**
20
- * The functions below are only called within the Dashboard
21
- *
22
  * Plugin constructor.
23
  */
24
  public function __construct()
@@ -109,14 +107,10 @@ class Plugin
109
  * /wp-content/cache/asset-cleanup/css/
110
  * /wp-content/cache/asset-cleanup/css/item/
111
  * /wp-content/cache/asset-cleanup/css/index.php
112
- * /wp-content/cache/asset-cleanup/css/logged-in/
113
- * /wp-content/cache/asset-cleanup/css/logged-in/index.php
114
  *
115
  * /wp-content/cache/asset-cleanup/js/
116
  * /wp-content/cache/asset-cleanup/js/item/
117
  * /wp-content/cache/asset-cleanup/js/index.php
118
- * /wp-content/cache/asset-cleanup/js/logged-in/
119
- * /wp-content/cache/asset-cleanup/js/logged-in/index.php
120
  *
121
  */
122
  self::createCacheFoldersFiles(array('css','js'));
@@ -192,6 +186,11 @@ SQL;
192
  public static function removeCacheDirWithoutAssets()
193
  {
194
  $pathToCacheDir = WP_CONTENT_DIR . OptimizeCommon::getRelPathPluginCacheDir();
 
 
 
 
 
195
  $pathToCacheDirCss = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir();
196
  $pathToCacheDirJs = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir();
197
 
@@ -255,21 +254,24 @@ HTACCESS;
255
  }
256
 
257
  if ( ! is_file( $cacheDir . 'index.php' ) ) {
258
- // /wp-content/cache/asset-cleanup/cache/{$assetType}/index.php
259
  FileSystem::file_put_contents( $cacheDir . 'index.php', $emptyPhpFileContents );
260
  }
261
 
262
- if ( ! is_dir( $cacheDir . 'logged-in' ) ) {
263
- @mkdir( $cacheDir . 'logged-in', 0755 );
264
- }
265
-
266
  if ( ! is_dir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir ) ) {
 
267
  @mkdir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir, 0755 );
268
  }
269
 
270
- if ( ! is_file( $cacheDir . 'logged-in/index.php' ) ) {
271
- // /wp-content/cache/asset-cleanup/cache/{$assetType}/logged-in/index.html
272
- FileSystem::file_put_contents( $cacheDir . 'logged-in/index.php', $emptyPhpFileContents );
 
 
 
 
 
 
273
  }
274
 
275
  $htAccessFilePath = dirname( $cacheDir ) . '/.htaccess';
@@ -357,7 +359,8 @@ HTACCESS;
357
  }
358
 
359
  /**
360
- * This works like /?wpacu_no_load with a fundamental difference:
 
361
  * It needs to be triggered through a very early 'init' action hook after all plugins are loaded, thus it can't be used in /early-triggers.php
362
  * e.g. in situations when the page is an AMP one, prevent any changes to the HTML source by Asset CleanUp Pro
363
  *
@@ -371,6 +374,12 @@ HTACCESS;
371
  return false;
372
  }
373
 
 
 
 
 
 
 
374
  if (defined('WPACU_PREVENT_ANY_CHANGES')) {
375
  return WPACU_PREVENT_ANY_CHANGES;
376
  }
@@ -388,6 +397,7 @@ HTACCESS;
388
  }
389
 
390
  if (array_key_exists('wpacu_clean_load', $_GET)) {
 
391
  return true;
392
  }
393
 
17
  const RATE_URL = 'https://wordpress.org/support/plugin/wp-asset-clean-up/reviews/?filter=5#new-post';
18
 
19
  /**
 
 
20
  * Plugin constructor.
21
  */
22
  public function __construct()
107
  * /wp-content/cache/asset-cleanup/css/
108
  * /wp-content/cache/asset-cleanup/css/item/
109
  * /wp-content/cache/asset-cleanup/css/index.php
 
 
110
  *
111
  * /wp-content/cache/asset-cleanup/js/
112
  * /wp-content/cache/asset-cleanup/js/item/
113
  * /wp-content/cache/asset-cleanup/js/index.php
 
 
114
  *
115
  */
116
  self::createCacheFoldersFiles(array('css','js'));
186
  public static function removeCacheDirWithoutAssets()
187
  {
188
  $pathToCacheDir = WP_CONTENT_DIR . OptimizeCommon::getRelPathPluginCacheDir();
189
+
190
+ if (! is_dir($pathToCacheDir)) {
191
+ return;
192
+ }
193
+
194
  $pathToCacheDirCss = WP_CONTENT_DIR . OptimizeCss::getRelPathCssCacheDir();
195
  $pathToCacheDirJs = WP_CONTENT_DIR . OptimizeJs::getRelPathJsCacheDir();
196
 
254
  }
255
 
256
  if ( ! is_file( $cacheDir . 'index.php' ) ) {
257
+ // /wp-content/cache/asset-cleanup/cache/(css|js)/index.php
258
  FileSystem::file_put_contents( $cacheDir . 'index.php', $emptyPhpFileContents );
259
  }
260
 
 
 
 
 
261
  if ( ! is_dir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir ) ) {
262
+ // /wp-content/cache/asset-cleanup/cache/(css|js)/item/
263
  @mkdir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir, 0755 );
264
  }
265
 
266
+ // For large inline STYLE & SCRIPT tags
267
+ if ( ! is_dir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline' ) ) {
268
+ // /wp-content/cache/asset-cleanup/cache/(css|js)/item/inline/
269
+ @mkdir( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline', 0755 );
270
+ }
271
+
272
+ if ( ! is_file( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline/index.php' ) ) {
273
+ // /wp-content/cache/asset-cleanup/cache/(css|js)/item/inline/index.php
274
+ FileSystem::file_put_contents( $cacheDir . OptimizeCommon::$optimizedSingleFilesDir.'/inline/index.php', $emptyPhpFileContents );
275
  }
276
 
277
  $htAccessFilePath = dirname( $cacheDir ) . '/.htaccess';
359
  }
360
 
361
  /**
362
+ * This works like /?wpacu_no_lo
363
+ * ad with a fundamental difference:
364
  * It needs to be triggered through a very early 'init' action hook after all plugins are loaded, thus it can't be used in /early-triggers.php
365
  * e.g. in situations when the page is an AMP one, prevent any changes to the HTML source by Asset CleanUp Pro
366
  *
374
  return false;
375
  }
376
 
377
+ // Perhaps the editor from "Pro" (theme.co) is on
378
+ if (apply_filters('wpacu_prevent_any_changes', false)) {
379
+ define('WPACU_PREVENT_ANY_CHANGES', true);
380
+ return true;
381
+ }
382
+
383
  if (defined('WPACU_PREVENT_ANY_CHANGES')) {
384
  return WPACU_PREVENT_ANY_CHANGES;
385
  }
397
  }
398
 
399
  if (array_key_exists('wpacu_clean_load', $_GET)) {
400
+ define('WPACU_PREVENT_ANY_CHANGES', true);
401
  return true;
402
  }
403
 
classes/Preloads.php CHANGED
@@ -92,7 +92,7 @@ class Preloads
92
  $preloads = $this->getPreloads();
93
 
94
  if (isset($preloads['styles']) && ! empty($preloads['styles'])) {
95
- $htmlSource = self::appendPreloadsForStylesToHead($htmlSource);
96
  }
97
 
98
  $htmlSource = str_replace(self::DEL_STYLES_PRELOADS, '', $htmlSource);
@@ -229,7 +229,8 @@ class Preloads
229
  }
230
 
231
  if (array_key_exists($handle, $this->preloads['styles']) && $this->preloads['styles'][$handle]) {
232
- return str_replace('<link ', '<link data-wpacu-to-be-preloaded-basic=\'1\' ', $htmlTag);
 
233
  }
234
 
235
  return $htmlTag;
@@ -269,25 +270,51 @@ class Preloads
269
 
270
  /**
271
  * @param $htmlSource
 
272
  *
273
  * @return mixed
274
  */
275
- public static function appendPreloadsForStylesToHead($htmlSource)
276
  {
277
- // Highest accuracy via DOMDocument
278
- if (function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('DOMDocument')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  $documentForCSS = new \DOMDocument();
280
  libxml_use_internal_errors(true);
281
 
282
- $documentForCSS->loadHTML($htmlSource);
 
 
283
  $linkTags = $documentForCSS->getElementsByTagName( 'link' );
284
 
285
- $matchesSourcesFromLinkTags = array();
286
 
287
  foreach ( $linkTags as $tagObject ) {
288
- if (! $tagObject->hasAttributes()) {
289
- continue;
290
- }
291
 
292
  $linkAttributes = array();
293
 
@@ -301,10 +328,7 @@ class Preloads
301
  }
302
 
303
  libxml_clear_errors();
304
- } else { // RegEx Fallback
305
- $strContainsFormat = preg_quote('data-wpacu-to-be-preloaded-basic=\'1\'', '/');
306
- preg_match_all('#<link[^>]'.$strContainsFormat.'[^>]*' . 'href=([\'"])(.*)([\'"])' . '.*(>)#Usmi', $htmlSource, $matchesSourcesFromLinkTags, PREG_SET_ORDER);
307
- }
308
 
309
  foreach ($matchesSourcesFromLinkTags as $linkTagArray) {
310
  $linkHref = isset($linkTagArray[2]) ? $linkTagArray[2] : false;
92
  $preloads = $this->getPreloads();
93
 
94
  if (isset($preloads['styles']) && ! empty($preloads['styles'])) {
95
+ $htmlSource = self::appendPreloadsForStylesToHead($htmlSource, array_keys($preloads['styles']));
96
  }
97
 
98
  $htmlSource = str_replace(self::DEL_STYLES_PRELOADS, '', $htmlSource);
229
  }
230
 
231
  if (array_key_exists($handle, $this->preloads['styles']) && $this->preloads['styles'][$handle]) {
232
+ ObjectCache::wpacu_cache_set($handle, 1, 'wpacu_basic_preload_handles');
233
+ return str_replace('<link ', '<link data-wpacu-to-be-preloaded-basic=\'1\' ', $htmlTag);
234
  }
235
 
236
  return $htmlTag;
270
 
271
  /**
272
  * @param $htmlSource
273
+ * @param $preloadedHandles
274
  *
275
  * @return mixed
276
  */
277
+ public static function appendPreloadsForStylesToHead($htmlSource, $preloadedHandles)
278
  {
279
+ // Perhaps it's not applicable in the current page (no LINK tags are loaded that should be preloaded)
280
+ if (strpos($htmlSource, 'data-wpacu-to-be-preloaded-basic') === false) {
281
+ return $htmlSource;
282
+ }
283
+
284
+ // Use the RegEx as it's much faster and very accurate in this situation
285
+ // If there are issues, fallback to DOMDocument
286
+ $strContainsFormat = preg_quote('data-wpacu-to-be-preloaded-basic', '/');
287
+ preg_match_all('#<link[^>]'.$strContainsFormat.'[^>]*' . 'href=(\'|"|)(.*)(\\1?\s)' . '.*(>)#Usmi', $htmlSource, $matchesSourcesFromLinkTags, PREG_SET_ORDER);
288
+
289
+ $stickToRegEx = true; // default
290
+
291
+ foreach ($matchesSourcesFromLinkTags as $linkTagArray) {
292
+ $linkTag = $linkTagArray[0];
293
+
294
+ preg_match_all('#id=([\'"])(.*?)(\\1)#', $linkTag, $matchId);
295
+ $matchedCssId = isset($matchId[2][0]) ? $matchId[2][0] : '';
296
+ $matchedCssHandle = substr($matchedCssId, 0, -4);
297
+
298
+ if (! in_array($matchedCssHandle, $preloadedHandles)) {
299
+ $stickToRegEx = false;
300
+ break;
301
+ }
302
+ }
303
+
304
+ // Something might not be right with the RegEx; Fallback to DOMDocument, more accurate, but slower
305
+ if (! $stickToRegEx && function_exists('libxml_use_internal_errors') && function_exists('libxml_clear_errors') && class_exists('\DOMDocument')) {
306
  $documentForCSS = new \DOMDocument();
307
  libxml_use_internal_errors(true);
308
 
309
+ $htmlSourceAlt = preg_replace( '@<(noscript|style|script)[^>]*?>.*?</\\1>@si', '', $htmlSource );
310
+ $documentForCSS->loadHTML($htmlSourceAlt);
311
+
312
  $linkTags = $documentForCSS->getElementsByTagName( 'link' );
313
 
314
+ $matchesSourcesFromLinkTags = array(); // reset its value; new fetch method was used
315
 
316
  foreach ( $linkTags as $tagObject ) {
317
+ if (empty($tagObject->attributes)) { continue; }
 
 
318
 
319
  $linkAttributes = array();
320
 
328
  }
329
 
330
  libxml_clear_errors();
331
+ }
 
 
 
332
 
333
  foreach ($matchesSourcesFromLinkTags as $linkTagArray) {
334
  $linkHref = isset($linkTagArray[2]) ? $linkTagArray[2] : false;
classes/Settings.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
4
- use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
5
  use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
6
  use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
7
 
@@ -55,7 +54,6 @@ class Settings
55
  'combine_loaded_css_for_admin_only', // Since v1.1.1.4 (Pro) & v1.3.1.1 (Lite)
56
 
57
  // [wpacu_pro]
58
- 'combine_loaded_css_append_handle_extra', // Adds any associated inline STYLE tags content to the combined files
59
  'defer_css_loaded_body',
60
  // [/wpacu_pro]
61
 
@@ -85,10 +83,6 @@ class Settings
85
  'combine_loaded_js_for_admin_only',
86
  'combine_loaded_js_defer_body', // Applies defer="defer" to the combined file(s) within BODY tag
87
 
88
- // [wpacu_pro]
89
- 'combine_loaded_js_append_handle_extra', // Adds any CDATA and other associated inline SCRIPT tags content to the combined files
90
- // [/wpacu_pro]
91
-
92
  // Minify each loaded CSS (remaining ones after unloading the useless ones)
93
  'minify_loaded_css',
94
  'minify_loaded_css_inline',
@@ -233,12 +227,7 @@ class Settings
233
  // [/wpacu_pro]
234
 
235
  'combine_loaded_css_exceptions' => '/plugins/wd-instagram-feed/(.*?).css',
236
- 'combine_loaded_css_append_handle_extra' => '1',
237
-
238
- 'combine_loaded_js_exceptions' => '/plugins/wd-instagram-feed/(.*?).js',
239
- // [wpacu_pro]
240
- 'combine_loaded_js_append_handle_extra' => '1',
241
- // [/wpacu_pro]
242
 
243
  // [wpacu_pro]
244
  'defer_css_loaded_body' => 'moved',
@@ -254,7 +243,7 @@ class Settings
254
 
255
  'fetch_cached_files_details_from' => 'disk', // Do not add more rows to the database by default (options table can become quite large)
256
 
257
- 'clear_cached_files_after' => '10'
258
  );
259
  }
260
 
1
  <?php
2
  namespace WpAssetCleanUp;
3
 
 
4
  use WpAssetCleanUp\OptimiseAssets\OptimizeCss;
5
  use WpAssetCleanUp\OptimiseAssets\OptimizeJs;
6
 
54
  'combine_loaded_css_for_admin_only', // Since v1.1.1.4 (Pro) & v1.3.1.1 (Lite)
55
 
56
  // [wpacu_pro]
 
57
  'defer_css_loaded_body',
58
  // [/wpacu_pro]
59
 
83
  'combine_loaded_js_for_admin_only',
84
  'combine_loaded_js_defer_body', // Applies defer="defer" to the combined file(s) within BODY tag
85
 
 
 
 
 
86
  // Minify each loaded CSS (remaining ones after unloading the useless ones)
87
  'minify_loaded_css',
88
  'minify_loaded_css_inline',
227
  // [/wpacu_pro]
228
 
229
  'combine_loaded_css_exceptions' => '/plugins/wd-instagram-feed/(.*?).css',
230
+ 'combine_loaded_js_exceptions' => '/plugins/wd-instagram-feed/(.*?).js',
 
 
 
 
 
231
 
232
  // [wpacu_pro]
233
  'defer_css_loaded_body' => 'moved',
243
 
244
  'fetch_cached_files_details_from' => 'disk', // Do not add more rows to the database by default (options table can become quite large)
245
 
246
+ 'clear_cached_files_after' => '7'
247
  );
248
  }
249
 
classes/Update.php CHANGED
@@ -66,6 +66,9 @@ HTML;
66
 
67
  // Clear cache (via AJAX) only if the user is logged-in (with the right privileges)
68
  add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_clear_cache', array($this, 'ajaxClearCache'), PHP_INT_MAX);
 
 
 
69
  }
70
 
71
  /**
@@ -136,6 +139,12 @@ HTML;
136
 
137
  // Form submitted from a Singular Page
138
  // e.g. post, page, custom post type such as 'product' page from WooCommerce, home page (static page selected as front page)
 
 
 
 
 
 
139
  if ($postId > 0) {
140
  $post = get_post($postId);
141
  $this->savePost($post->ID, $post);
@@ -976,7 +985,43 @@ HTML;
976
  foreach ($assetDataHandleList as $assetObj) {
977
  $assetArray = (array)$assetObj;
978
  $assetHandle = $assetArray['handle'];
979
- unset($assetArray['handle']); // no need to have it twice
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
980
  $existingList[$assetKey][$globalKey][$assetHandle] = $assetArray;
981
  }
982
  }
@@ -1003,8 +1048,35 @@ HTML;
1003
  exit();
1004
  }
1005
 
1006
- OptimizeCommon::clearAllCache();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1007
 
 
 
 
 
 
 
 
 
 
1008
  exit();
1009
- }
1010
  }
66
 
67
  // Clear cache (via AJAX) only if the user is logged-in (with the right privileges)
68
  add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_clear_cache', array($this, 'ajaxClearCache'), PHP_INT_MAX);
69
+
70
+ // After an update, preload the page for the guest view (the preload for the admin is done within script.min.js own plugin file)
71
+ add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_preload', array($this, 'ajaxPreloadGuest'), PHP_INT_MAX);
72
  }
73
 
74
  /**
139
 
140
  // Form submitted from a Singular Page
141
  // e.g. post, page, custom post type such as 'product' page from WooCommerce, home page (static page selected as front page)
142
+
143
+ // Sometimes, there's a singular page set as 404 page (e.g. via "404page – your smart custom 404 error page" plugin)
144
+ if (is_404() && Misc::getVar('post', 'wpacu_is_singular_page')) {
145
+ $postId = (int)$_POST['wpacu_is_singular_page'];
146
+ }
147
+
148
  if ($postId > 0) {
149
  $post = get_post($postId);
150
  $this->savePost($post->ID, $post);
985
  foreach ($assetDataHandleList as $assetObj) {
986
  $assetArray = (array)$assetObj;
987
  $assetHandle = $assetArray['handle'];
988
+
989
+ // Strip other unused information including the 'handle' (no need to have it twice as it's already in one of the array's keys)
990
+ unset( $assetArray['handle'], $assetArray['textdomain'], $assetArray['translations_path'] );
991
+
992
+ // Some handles don't have an "src" value such as "woocommerce-inline"
993
+ if (isset($assetArray['src']) && $assetArray['src']) {
994
+ $assetArray['src'] = Misc::assetFromHrefToRelativeUri( $assetArray['src'], $assetKey );
995
+ }
996
+
997
+ // [wpacu_pro]
998
+ if (isset($assetArray['output'])) { // hardcoded assets have an 'output' value
999
+ // Is there already an entry for the same handle with a value set for 'output' and 'output_min'
1000
+ if (isset($existingList[$assetKey][$globalKey][$assetHandle]['output'], $existingList[$assetKey][$globalKey][$assetHandle]['output_min'])) {
1001
+ // Save resources: do not update the same values and skip the minification (good to avoid large inline content)
1002
+ continue;
1003
+ }
1004
+
1005
+ if ( ! isset( $assetArray['output_min'] ) ) {
1006
+ $assetArray['output_min'] = '';
1007
+
1008
+ // Reference: $wpacuHardcodedInfoToStoreAfterSubmit from _assets-hardcoded-list.php
1009
+ if ( strpos( $assetHandle, 'wpacu_hardcoded_script_' ) === 0 ) {
1010
+ $outputMin = \WpAssetCleanUp\OptimiseAssets\MinifyJs::applyMinification( $assetArray['output'] );
1011
+ if ( $assetArray['output'] !== $outputMin ) {
1012
+ $assetArray['output_min'] = $outputMin;
1013
+ }
1014
+ } elseif ( ( strpos( $assetHandle, 'wpacu_hardcoded_link_' ) === 0 ) || ( strpos( $assetHandle,
1015
+ 'wpacu_hardcoded_style_' ) === 0 ) ) {
1016
+ $outputMin = \WpAssetCleanUp\OptimiseAssets\MinifyCss::applyMinification( $assetArray['output'] );
1017
+ if ( $assetArray['output'] !== $outputMin ) {
1018
+ $assetArray['output_min'] = $outputMin;
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+ // [/wpacu_pro]
1024
+
1025
  $existingList[$assetKey][$globalKey][$assetHandle] = $assetArray;
1026
  }
1027
  }
1048
  exit();
1049
  }
1050
 
1051
+ OptimizeCommon::clearCache();
1052
+ exit();
1053
+ }
1054
+
1055
+ /**
1056
+ * This is triggered when /admin/admin-ajax.php is called (default WordPress AJAX handler)
1057
+ */
1058
+ public function ajaxPreloadGuest()
1059
+ {
1060
+ if (! Menu::userCanManageAssets()) {
1061
+ echo 'Error: Not enough privileges to perform this action.';
1062
+ exit();
1063
+ }
1064
+
1065
+ $pageUrl = isset($_POST['page_url']) ? $_POST['page_url'] : false;
1066
+
1067
+ $pageUrlPreload = add_query_arg( array(
1068
+ 'wpacu_preload' => 1
1069
+ ), $pageUrl );
1070
 
1071
+ if (! filter_var($pageUrlPreload, FILTER_VALIDATE_URL)) {
1072
+ echo 'The URL `'.$pageUrlPreload.'` is not valid.';
1073
+ exit();
1074
+ }
1075
+
1076
+ $response = wp_remote_get($pageUrlPreload);
1077
+
1078
+ echo 'Page URL (preload): '.$pageUrlPreload."\n\n";
1079
+ echo $response['body'];
1080
  exit();
1081
+ }
1082
  }
early-triggers.php CHANGED
@@ -5,7 +5,17 @@ if (! defined('ABSPATH')) {
5
  }
6
 
7
  if (array_key_exists('wpacu_clean_load', $_GET)) {
8
- $_GET['ao_noptimize'] = 1;
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
  if (! function_exists('assetCleanUpHasNoLoadMatches')) {
@@ -198,6 +208,21 @@ if (! function_exists('assetCleanUpNoLoad')) {
198
  return true;
199
  }
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  // Perfmatters: Script Manager
202
  if (isset($_GET['perfmatters'])) {
203
  return true;
@@ -256,22 +281,22 @@ if (! function_exists('assetCleanUpNoLoad')) {
256
  }
257
 
258
  // Stop triggering Asset CleanUp (completely) on specific front-end pages
259
- // Do the trigger here (as early as possible)
260
  if (assetCleanUpHasNoLoadMatches()) {
261
  // Only use exit() when "wpassetcleanup_load" is used
262
  if (isset($_REQUEST['wpassetcleanup_load']) && $_REQUEST['wpassetcleanup_load']) {
263
- include_once(ABSPATH . 'wp-includes/pluggable.php');
264
-
265
- if (current_user_can('manage_options')) {
266
- $msg = sprintf(
267
- __(
268
- 'This page\'s URL is matched by one of the RegEx rules you have in <em>"Settings"</em> -&gt; <em>"Plugin Usage Preferences"</em> -&gt; <em>"Do not load the plugin on certain pages"</em>, thus %s is not loaded on that page and no CSS/JS are to be managed. If you wish to view the CSS/JS manager, please remove the matching RegEx rule and the list of CSS/JS will be fetched.',
269
- 'wp-asset-clean-up'
270
- ),
271
- WPACU_PLUGIN_TITLE
272
- );
273
- exit( $msg );
274
- }
275
  }
276
 
277
  return true;
@@ -285,3 +310,27 @@ if (! function_exists('assetCleanUpNoLoad')) {
285
  if (! defined('JSON_ERROR_NONE')) {
286
  define('JSON_ERROR_NONE', 0);
287
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  }
6
 
7
  if (array_key_exists('wpacu_clean_load', $_GET)) {
8
+ // Autoptimize
9
+ $_GET['ao_noptimize'] = $_REQUEST['ao_noptimize'] = '1';
10
+
11
+ // LiteSpeed Cache
12
+ if ( ! defined( 'LITESPEED_DISABLE_ALL' ) ) {
13
+ define('LITESPEED_DISABLE_ALL', true);
14
+ }
15
+
16
+ add_action( 'litespeed_disable_all', static function($reason) {
17
+ do_action( 'litespeed_debug', '[API] Disabled_all due to: A clean load of the page was requested via '. WPACU_PLUGIN_TITLE );
18
+ } );
19
  }
20
 
21
  if (! function_exists('assetCleanUpHasNoLoadMatches')) {
208
  return true;
209
  }
210
 
211
+ // "Pro" (theme.co) (iFrame)
212
+ if (isset($_POST['_cs_nonce'], $_POST['cs_preview_state']) && $_POST['_cs_nonce'] && $_POST['cs_preview_state']) {
213
+ return true;
214
+ }
215
+
216
+ // "Page Builder: Live Composer" plugin
217
+ if (defined('DS_LIVE_COMPOSER_ACTIVE') && DS_LIVE_COMPOSER_ACTIVE) {
218
+ return true;
219
+ }
220
+
221
+ // "WP Page Builder" plugin (By Themeum.com)
222
+ if (isset($_GET['load_for']) && $_GET['load_for'] === 'wppb_editor_iframe') {
223
+ return true;
224
+ }
225
+
226
  // Perfmatters: Script Manager
227
  if (isset($_GET['perfmatters'])) {
228
  return true;
281
  }
282
 
283
  // Stop triggering Asset CleanUp (completely) on specific front-end pages
284
+ // Do the trigger here and if necessary exit as early as possible to save resources via "registered_taxonomy" action hook)
285
  if (assetCleanUpHasNoLoadMatches()) {
286
  // Only use exit() when "wpassetcleanup_load" is used
287
  if (isset($_REQUEST['wpassetcleanup_load']) && $_REQUEST['wpassetcleanup_load']) {
288
+ add_action('registered_taxonomy', function() {
289
+ if ( current_user_can( 'manage_options' ) ) {
290
+ $msg = sprintf(
291
+ __(
292
+ 'This page\'s URL is matched by one of the RegEx rules you have in <em>"Settings"</em> -&gt; <em>"Plugin Usage Preferences"</em> -&gt; <em>"Do not load the plugin on certain pages"</em>, thus %s is not loaded on that page and no CSS/JS are to be managed. If you wish to view the CSS/JS manager, please remove the matching RegEx rule and the list of CSS/JS will be fetched.',
293
+ 'wp-asset-clean-up'
294
+ ),
295
+ WPACU_PLUGIN_TITLE
296
+ );
297
+ exit( $msg );
298
+ }
299
+ });
300
  }
301
 
302
  return true;
310
  if (! defined('JSON_ERROR_NONE')) {
311
  define('JSON_ERROR_NONE', 0);
312
  }
313
+
314
+ // Make sure the plugin doesn't load when the editor of either "X" theme or "Pro" website creator (theme.co) is ON
315
+ add_action('init', static function() {
316
+ if (is_admin()) {
317
+ return; // Not relevant for the Dashboard view, stop here!
318
+ }
319
+
320
+ if (class_exists('\WpAssetCleanUp\Menu') && \WpAssetCleanUp\Menu::userCanManageAssets() && method_exists('Cornerstone_Common', 'get_app_slug') && in_array(get_stylesheet(), array('x', 'pro'))) {
321
+ $customAppSlug = get_stylesheet(); // default one ('x' or 'pro')
322
+
323
+ // Is there any custom slug set in "/wp-admin/admin.php?page=cornerstone-settings"?
324
+ // "Settings" -> "Custom Path" (check it out below)
325
+ $cornerStoneSettings = get_option('cornerstone_settings');
326
+ if (isset($cornerStoneSettings['custom_app_slug']) && $cornerStoneSettings['custom_app_slug'] !== '') {
327
+ $customAppSlug = $cornerStoneSettings['custom_app_slug'];
328
+ }
329
+
330
+ $lengthToUse = strlen($customAppSlug) + 2; // add the slashes to the count
331
+
332
+ if (substr($_SERVER['REQUEST_URI'], -$lengthToUse) === '/'.$customAppSlug.'/') {
333
+ add_filter( 'wpacu_prevent_any_changes', '__return_true' );
334
+ }
335
+ }
336
+ });
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: gabelivan
3
  Tags: minify css, minify javascript, defer css javascript, page speed, dequeue, performance
4
  Donate link: https://www.gabelivan.com/items/wp-asset-cleanup-pro/?utm_source=wp_org_lite&utm_medium=donate
5
  Requires at least: 4.5
6
- Tested up to: 5.4
7
- Stable tag: 1.3.6.1
8
  License: GPLv3
9
  License URI: http://www.gnu.org/licenses/gpl.html
10
 
@@ -179,6 +179,30 @@ With the recently released "Test Mode" feature, you can safely unload assets on
179
  4. Homepage CSS & JS Management (List sorted by location)
180
 
181
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  = 1.3.6.1 =
183
  * Increased the speed of unloading (dequeueing) styles & scripts by ~40ms (caching is used to avoid calling the same PHP code during several action hooks)
184
  * Higher accuracy in stripping 'before' and 'after' associated inline SCRIPT after adding the content to the JS combined file
@@ -196,6 +220,7 @@ With the recently released "Test Mode" feature, you can safely unload assets on
196
  * Trigger certain actions (to save database & disk space) when the plugin is deactivated: Clear all its transients from the database & Remove the caching directory if it doesn't have any more CSS/JS; If all the plugin's changes were cleared via "Tools" -> "Reset", then deactivating the plugin will completely clear any of its traces
197
  * The plugin's own files that are needed for the plugin's functionality (they are only loading for the logged-in admin), are loaded asynchronously (CSS) and deferred (JS) to ensure the admin doesn't load them as render-blocking especially when managing the pages in the front-end view
198
  * The combined CSS tags can now be altered for any reason via add_filter() through the 'wpacu_combined_css_tag' tag name, just like the combined JS tags are via 'wpacu_combined_js_tag'
 
199
  * Fix: Remove request to non-existent CSS file within the Dashboard that generated a 404 Not Found error in the browser's console (harmless, but confusing)
200
 
201
  = 1.3.6.0 =
3
  Tags: minify css, minify javascript, defer css javascript, page speed, dequeue, performance
4
  Donate link: https://www.gabelivan.com/items/wp-asset-cleanup-pro/?utm_source=wp_org_lite&utm_medium=donate
5
  Requires at least: 4.5
6
+ Tested up to: 5.4.1
7
+ Stable tag: 1.3.6.2
8
  License: GPLv3
9
  License URI: http://www.gnu.org/licenses/gpl.html
10
 
179
  4. Homepage CSS & JS Management (List sorted by location)
180
 
181
  == Changelog ==
182
+ = 1.3.6.2 =
183
+ * Once a page is updated, the plugin preloads that page for both the admin and the guest visitor, making sure any new changes would take effect, saving the admin's time and making sure any first visitor coming to that page will access it faster (not having to wait for the caching to re-built)
184
+ * If the attribute "data-wpacu-skip" is applied to any CSS/JS, then no alteration (e.g. no minify and no addition to any combine list) will be applied to that file (apart from the actual unload or attributes such as async/defer)
185
+ * 'Remove All "generator" meta tags?' improvement: Higher accuracy in stripping META tag generators if the option is enabled in case some of their attributes have no quotes around them (rare cases)
186
+ * If 'Remove "REST API" link tag?' is enabled, the /wp-json/ reference is also removed from the "Response headers" when accessing the page via remove_action()
187
+ * Compatibility with extra page builders: "X" & "PRO" themes (Theme.co), "WP Page Builder" & "Page Builder: Live Composer" plugins: whenever their editor is ON, no unloads or any other changes to the HTML source (including minification) are performed to make sure the editor is loading its files and works smoothly
188
+ * Compatibility with "Redis Object Cache" plugin: The global variable $wp_object_cache from the WordPress core is no longer used and it's replaced with a custom solution
189
+ * Compatibility with "404page – your smart custom 404 error page" plugin and similar plugins that are making pages as 404 customizable ones
190
+ * For debugging purposes, the admin can use /?wpacu_no_cache to view how the website would load without the CSS/JS cache applied (the files will still be referenced from the caching directory but they will be dynamically generated instead)
191
+ * Sometimes, large inline STYLE/SCRIPT tags' content has to be minified; if it's between 40KB and 500 KB it will be cached; any tags' content over 500KB will not be minified as it would use too many resources; it's advisable to put very large tag content into a .js external file as it would affect the TTFB (time to the first byte) when the page is loaded
192
+ * Any inline CSS/JS associated with a handle (generated via wp_add_inline_style() and wp_add_inline_script() respectively) are automatically added to the combined file
193
+ * Combined CSS/JS files are all stored in /wp-content/cache/asset-cleanup/("css" or "js")/ to avoid duplicated files that used to be stored in "logged-in" directory which is no longer created; This reduces the total disk space especially when the same CSS/JS is created (sometimes these files are quite large) for both guests & logged-in users
194
+ * If "Combine loaded CSS (Stylesheets) into fewer files" is enabled, the LINK tags that are preloaded (at least two of them) will also be combined, thus reducing the number of HTTP requests
195
+ * The method loadHTML() from DOMDocument is processing tags faster as the initial HTML source passed to it as a parameter goes through several filters, making it much smaller which makes a different in page speed when it comes to large HTML sources
196
+ * Prevent certain DOMDocument calls (which can be slow on large HTML documents) when they are not necessary (e.g. when preloading CSS stylesheets and the RegEx which is faster can do the same task with the same accuracy)
197
+ * Strip LINK tags that are pointing to empty content (including any inline code associated with the enqueued style added via wp_add_inline_style() function) if "CSS Files Minification" is enabled, making sure any empty tags are also stripped when "Inline CSS Files" is enabled, this saving HTTP requests and having less DOM elements
198
+ * In some cases, the PHP function strtr() has proven to be faster than str_replace() to make replacements, thus it has been applied to some methods that are dealing with the alteration of the HTML source
199
+ * Notify the admin that unloading 'jquery-migrate' won't unload it's "child" as well, 'jquery' (as it's a special case)
200
+ * Fix: In rare cases, URLs to the assets are starting with ../ (it's not the best practice as this would only work depending on the page's URL structure); Make sure the file's size is calculated correctly and the right URL for the file is checked in the background to determine if it returns a 200 OK response or not
201
+ * Fix: Store the assets info (which are shown only within the Dashboard for reference purposes) with the relative location (UR) to the asset, in case the data is later imported from a Staging to Live environment, it won't show any Staging URLs on the Live website on pages such as "Overview", thus avoiding any confusion the admin might have
202
+ * Fix: Make sure the time dequeueing CSS/JS is calculated correctly
203
+ * Fix: If "Asynchronous via Web Font Loader (webfont.js)" was chosen for "Combine Multiple Requests Into Fewer Ones", the font weights weren't added to the final generated SCRIPT tag
204
+ * Fix: Make sure when the handle information is saved, there are no PHP notice errors if the 'src' index is missing as some handles do not have an "src"
205
+
206
  = 1.3.6.1 =
207
  * Increased the speed of unloading (dequeueing) styles & scripts by ~40ms (caching is used to avoid calling the same PHP code during several action hooks)
208
  * Higher accuracy in stripping 'before' and 'after' associated inline SCRIPT after adding the content to the JS combined file
220
  * Trigger certain actions (to save database & disk space) when the plugin is deactivated: Clear all its transients from the database & Remove the caching directory if it doesn't have any more CSS/JS; If all the plugin's changes were cleared via "Tools" -> "Reset", then deactivating the plugin will completely clear any of its traces
221
  * The plugin's own files that are needed for the plugin's functionality (they are only loading for the logged-in admin), are loaded asynchronously (CSS) and deferred (JS) to ensure the admin doesn't load them as render-blocking especially when managing the pages in the front-end view
222
  * The combined CSS tags can now be altered for any reason via add_filter() through the 'wpacu_combined_css_tag' tag name, just like the combined JS tags are via 'wpacu_combined_js_tag'
223
+ * While the CSS/JS assets are fetched prevent extra performance plugins from triggering their optimisation for CSS/JS/HTML as the action is irrelevant and uses resources during the fetching of the assets for the admin
224
  * Fix: Remove request to non-existent CSS file within the Dashboard that generated a 404 Not Found error in the browser's console (harmless, but confusing)
225
 
226
  = 1.3.6.0 =
templates/_admin-page-settings-plugin-areas/_optimize-css.php CHANGED
@@ -160,16 +160,9 @@ $availableForPro = '<a class="go-pro-link-no-style" target="_blank" href="' . WP
160
  </label>
161
  </p>
162
 
163
- <!-- [wpacu_lite] -->
164
- <div style="padding: 10px; background: #f2faf2;" class="wpacu-fancy-checkbox">
165
- <?php echo $availableForPro; ?>&nbsp;
166
- <input id="combine_loaded_css_append_handle_extra_checkbox"
167
- disabled="disabled"
168
- type="checkbox" />
169
- <label for="combine_loaded_css_append_handle_extra_checkbox">Add inline tag contents associated with a style (handle) to the combined group of files before/after the main script's contents</label>
170
- <p style="margin-top: 10px;"><small>When a file is added to a combined group of files, any other inline content (e.g. added via <code style="font-size: inherit;">wp_add_inline_style()</code>) associated with it, will also be added to the combined files. This reduces the number of DOM elements as well makes sure the CSS code will load in the right (set) order.</small></p>
171
- </div>
172
- <!-- [/wpacu_lite] -->
173
 
174
  <div id="wpacu_combine_loaded_css_exceptions_area">
175
  <div style="margin: 8px 0 6px;"><?php _e('Do not combine the CSS files matching the patterns below', 'wp-asset-clean-up'); ?> (<?php _e('one per line', 'wp-asset-clean-up'); ?>):</div>
@@ -185,10 +178,7 @@ $availableForPro = '<a class="go-pro-link-no-style" target="_blank" href="' . WP
185
  </div>
186
 
187
  <p>This scans the remaining CSS files (left after cleaning up the unnecessary ones) from the <code>&lt;head&gt;</code> and <code>&lt;body&gt;</code> locations and combines them into ~2 files (one in each location). To be 100% sure everything works fine after activation, consider enabling this feature only for logged-in administrator, so only you can see the updated page. If all looks good, you can later uncheck the option to apply the feature to everyone else.</p>
188
- <p style="margin: 8px 0 4px;"><span style="color: #ffc107;" class="dashicons dashicons-lightbulb"></span> The following stylesheets are not included in the combined CSS files (split in groups depending on the "media" attribute value) for maximum performance:</p>
189
- <ul style="list-style: disc; margin-top: 0; margin-left: 35px; margin-bottom: 0;">
190
- <li style="margin-bottom: 0;">Have any <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content">preloading added to them</a> via <code>rel="preload"</code> will not be combined as they have priority in loading and shouldn't be mixed with the rest of the CSS.</li>
191
- </ul>
192
  <hr />
193
  <p style="margin: 8px 0 4px;"><span style="color: #ffc107;" class="dashicons dashicons-lightbulb"></span> This feature will not work <strong>IF</strong>:</p>
194
  <ul style="margin-top: 0; margin-left: 35px; list-style: disc;">
160
  </label>
161
  </p>
162
 
163
+ <p style="margin-top: 10px;"><strong>Note:</strong> When a stylesheet is added to a combined group of files, any other inline content (e.g. added via <code style="font-size: inherit;">wp_add_inline_style()</code>) associated with it, will also be added to the combined files. This reduces the number of DOM elements as well makes sure the CSS code will load in the right (set) order.</p>
164
+
165
+ <hr />
 
 
 
 
 
 
 
166
 
167
  <div id="wpacu_combine_loaded_css_exceptions_area">
168
  <div style="margin: 8px 0 6px;"><?php _e('Do not combine the CSS files matching the patterns below', 'wp-asset-clean-up'); ?> (<?php _e('one per line', 'wp-asset-clean-up'); ?>):</div>
178
  </div>
179
 
180
  <p>This scans the remaining CSS files (left after cleaning up the unnecessary ones) from the <code>&lt;head&gt;</code> and <code>&lt;body&gt;</code> locations and combines them into ~2 files (one in each location). To be 100% sure everything works fine after activation, consider enabling this feature only for logged-in administrator, so only you can see the updated page. If all looks good, you can later uncheck the option to apply the feature to everyone else.</p>
181
+
 
 
 
182
  <hr />
183
  <p style="margin: 8px 0 4px;"><span style="color: #ffc107;" class="dashicons dashicons-lightbulb"></span> This feature will not work <strong>IF</strong>:</p>
184
  <ul style="margin-top: 0; margin-left: 35px; list-style: disc;">
templates/_admin-page-settings-plugin-areas/_optimize-js.php CHANGED
@@ -153,16 +153,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
153
  </label>
154
  </p>
155
 
156
- <div style="padding: 10px; background: #f2faf2;" class="wpacu-fancy-checkbox">
157
- <?php echo $availableForProAppendInlineJs; ?>&nbsp;
158
- <input style="opacity: 0.4;" id="combine_loaded_js_append_handle_extra_checkbox"
159
- <?php echo (($data['combine_loaded_js_append_handle_extra'] == 1) ? 'checked="checked"' : ''); ?>
160
- type="checkbox"
161
- name="<?php echo WPACU_PLUGIN_ID . '_settings'; ?>[combine_loaded_js_append_handle_extra]"
162
- value="1" />
163
- <label for="combine_loaded_js_append_handle_extra_checkbox">Add inline tag contents associated with a script (handle) to the combined group of files before/after the main script's contents</label>
164
- <p style="margin-top: 10px;"><small>When a file is added to a combined group of files, the CDATA as well as any other inline content (e.g. added via <code style="font-size: inherit;">wp_add_inline_script()</code>) associated with it will also be added to the combined files. This reduces the number of DOM elements as well makes sure that, in case, the combined file is deferred, the code from the inline tags is triggered at the same time as the one from the file</small></p>
165
- </div>
166
 
167
  <p style="padding: 10px; background: #f2faf2;">
168
  <label for="wpacu_combine_loaded_js_defer_body_checkbox">
@@ -261,7 +252,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
261
  }
262
  ?>
263
 
264
- <div id="wpacu_inline_js_files_info_area" style="opacity: 0.4;">
265
  <p class="wpacu-warning" style="margin: 10px 0; font-size: 13px; padding: 4px 9px;">
266
  <small><strong style="color: orange;"><span class="dashicons dashicons-warning"></span></strong> Please be extra careful if you decide to use this feature as inlining JavaScript files can be trickier than inlining CSS ones due to the more complex syntax and various attributes that might set to the external JS file such as "async" and "defer" (files having this attribute will be called via <em>DOMContentLoaded</em> event).</small>
267
  </p>
@@ -324,6 +315,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
324
  </td>
325
  </tr>
326
 
 
327
  <tr valign="top">
328
  <th scope="row" class="setting_title">
329
  <label for="wpacu_move_scripts_to_body_enable"><?php _e('Move All <code>&lt;SCRIPT&gt;</code> tags From HEAD to BODY', 'wp-asset-clean-up'); ?> <?php echo $availableForProMoveScriptsToBody; ?></label>
@@ -361,6 +353,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
361
  </div>
362
  </td>
363
  </tr>
 
364
 
365
  <tr valign="top">
366
  <th scope="row" class="setting_title">
@@ -450,8 +443,8 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
450
  <code>&lt;script type="text/javascript" src="/wp-includes/js/jquery.js"&gt;&lt;/script&gt;</code><br />
451
  <code>&lt;script type="text/javascript" src="/wp-includes/js/jquery-migrate.min.js"&gt;&lt;/script&gt;</code><br />
452
  <code>&lt;script type="text/javascript"&gt;jQuery(document).ready(function($) { /* code here */ });&lt;/script&gt;</code><br />
453
- <code>&lt;script type="text/javascript"&gt;$(document).ready(function() { /* another code here */ });&lt;/script&gt;</code> </p>
454
-
455
  </div>
456
  </div>
457
 
@@ -461,7 +454,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
461
  <h2 style="margin-top: 5px;"><?php _e('Examples of SCRIPTS moved from HEAD to BODY', 'wp-asset-clean-up'); ?></h2>
462
 
463
  <span><strong>FROM</strong></span>
464
- <pre style="margin-top: 4px; margin-bottom: 8px;">
465
  <code>&lt;head&gt;</code>
466
  <code>&lt;title&gt;Your page title here&lt;/title&gt;</code>
467
  <code>...</code>
@@ -477,7 +470,7 @@ $availableForProMoveScriptsToBody = '<a class="go-pro-link-no-style" target="_bl
477
  <div style="margin-top: -6px; margin-bottom: 14px;"><hr /></div>
478
 
479
  <span><strong>TO</strong></span>
480
- <pre style="margin-top: 4px; margin-bottom: 0;">
481
  <code>&lt;head&gt;</code>
482
  <code>&lt;title>Your page title here&lt;/title&gt;</code>
483
  <code>...</code>
153
  </label>
154
  </p>
155
 
156
+ <p style="margin-top: 10px;"><strong>Note:</strong> When a file is added to a combined group of files, the CDATA as well as any other inline content (e.g. added via <code style="font-size: inherit;">wp_add_inline_script()</code>) associated with it will also be added to the combined files. This reduces the number of DOM elements as well makes sure that, in case, the combined file is deferred, the code from the inline tags is triggered at the same time as the one from the file</p>
 
 
 
 
 
 
 
 
 
157
 
158
  <p style="padding: 10px; background: #f2faf2;">
159
  <label for="wpacu_combine_loaded_js_defer_body_checkbox">
252
  }
253
  ?>
254
 
255
+ <div id="wpacu_inline_js_files_info_area" <?php if (empty($data['is_optimize_css_enabled_by_other_party']) && $data['inline_js_files'] == 1) { ?> style="opacity: 1;" <?php } else { ?>style="opacity: 0.4;"<?php } ?>>
256
  <p class="wpacu-warning" style="margin: 10px 0; font-size: 13px; padding: 4px 9px;">
257
  <small><strong style="color: orange;"><span class="dashicons dashicons-warning"></span></strong> Please be extra careful if you decide to use this feature as inlining JavaScript files can be trickier than inlining CSS ones due to the more complex syntax and various attributes that might set to the external JS file such as "async" and "defer" (files having this attribute will be called via <em>DOMContentLoaded</em> event).</small>
258
  </p>
315
  </td>
316
  </tr>
317
 
318
+ <!-- [wpacu_pro] -->
319
  <tr valign="top">
320
  <th scope="row" class="setting_title">
321
  <label for="wpacu_move_scripts_to_body_enable"><?php _e('Move All <code>&lt;SCRIPT&gt;</code> tags From HEAD to BODY', 'wp-asset-clean-up'); ?> <?php echo $availableForProMoveScriptsToBody; ?></label>
353
  </div>
354
  </td>
355
  </tr>
356
+ <!-- [/wpacu_pro] -->
357
 
358
  <tr valign="top">
359
  <th scope="row" class="setting_title">
443
  <code>&lt;script type="text/javascript" src="/wp-includes/js/jquery.js"&gt;&lt;/script&gt;</code><br />
444
  <code>&lt;script type="text/javascript" src="/wp-includes/js/jquery-migrate.min.js"&gt;&lt;/script&gt;</code><br />
445
  <code>&lt;script type="text/javascript"&gt;jQuery(document).ready(function($) { /* code here */ });&lt;/script&gt;</code><br />
446
+ <code>&lt;script type="text/javascript"&gt;$(document).ready(function() { /* another code here */ });&lt;/script&gt;</code>
447
+ </p>
448
  </div>
449
  </div>
450
 
454
  <h2 style="margin-top: 5px;"><?php _e('Examples of SCRIPTS moved from HEAD to BODY', 'wp-asset-clean-up'); ?></h2>
455
 
456
  <span><strong>FROM</strong></span>
457
+ <pre style="margin-top: 4px; margin-bottom: 8px; white-space: pre;">
458
  <code>&lt;head&gt;</code>
459
  <code>&lt;title&gt;Your page title here&lt;/title&gt;</code>
460
  <code>...</code>
470
  <div style="margin-top: -6px; margin-bottom: 14px;"><hr /></div>
471
 
472
  <span><strong>TO</strong></span>
473
+ <pre style="margin-top: 4px; margin-bottom: 0; white-space: pre;">
474
  <code>&lt;head&gt;</code>
475
  <code>&lt;title>Your page title here&lt;/title&gt;</code>
476
  <code>...</code>
templates/_admin-page-settings-plugin-areas/_plugin-usage-settings.php CHANGED
@@ -455,19 +455,4 @@ foreach (\WpAssetCleanUp\MetaBoxes::$noMetaBoxesForPostTypes as $noMetaBoxesForP
455
  </div>
456
  </div>
457
 
458
- <!-- removeIf(development) -->
459
- <!-- [wpacu_lite] -->
460
- <!--
461
- <div id="wpacu-deactivate-modal-info" class="wpacu-modal" style="padding-top: 60px;">
462
- <div class="wpacu-modal-content" style="max-width: 650px;">
463
- <span class="wpacu-close">&times;</span>
464
- <h2 style="margin-top: 5px;"><?php _e('Asset CleanUp: Deactivation Modal', 'wp-asset-clean-up'); ?></h2>
465
- <p>When you use the "Deactivate" link for "Asset CleanUp: Page Speed Booster" plugin from "Plugins" -&gt; "Installed Plugins", a popup like the one in the below example shows up allowing you the option to <em>Skip &amp; Deactivate</em> or select an uninstall reason, sending your feedback and deactivate it. Collecting feedback is very useful to understand why you decided to deactivate the plugin so we can further improve it based on the overall feedback.</p>
466
- <p>However, there are times when you might do debugging on your website and you have to often deactivate the plugin. You can disable the feedback modal and you will not be asked for any uninstall reason anytime you use the "Deactivate" link.</p>
467
- <hr />
468
- <img style="margin: 0 auto; width: 100%; max-width: 500px; display: table;" src="<?php echo WPACU_PLUGIN_URL. '/assets/images/wpacu-deactivate-modal.jpg'; ?>" alt="" />
469
- </div>
470
- </div>
471
- -->
472
- <!-- [/wpacu_lite] -->
473
- <!-- endRemoveIf(development) -->
455
  </div>
456
  </div>
457
 
458
+ <!-- -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/meta-box-loaded-assets/_asset-script-single-row/_handle.php CHANGED
@@ -31,21 +31,39 @@ if ( ! isset($data, $isCoreFile, $hideCoreFiles, $jqueryIconHtmlHandle, $childHa
31
  if (! empty($childHandles)) {
32
  $ignoreChild = (isset($data['ignore_child']['scripts'][$data['row']['obj']->handle]) && $data['ignore_child']['scripts'][$data['row']['obj']->handle]);
33
  ?>
34
- <p>
35
- <em style="font-size: 85%;">
36
- <span style="color: #0073aa; width: 19px; height: 19px; vertical-align: middle;" class="dashicons dashicons-info"></span>
37
- This file has other JavaScript "children" files depending on it, thus, by unloading it, the following will also be unloaded:
38
- <span style="color: green; font-weight: 600;">
39
- <?php echo implode('<span style="color: black;">,</span> ', $childHandles); ?>
40
- </span>
41
- </em>
42
- <label for="script_<?php echo $data['row']['obj']->handle; ?>_ignore_children">
43
- &#10230; <input id="script_<?php echo $data['row']['obj']->handle; ?>_ignore_children"
44
- type="checkbox"
45
- <?php if ($ignoreChild) { ?>checked="checked"<?php } ?>
46
- name="wpacu_ignore_child[scripts][<?php echo $data['row']['obj']->handle; ?>]"
47
- value="1" /> <small><?php _e('Ignore dependency rule and keep the "children" loaded', 'wp-asset-clean-up'); ?></small>
48
- </label>
49
- </p>
50
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
31
  if (! empty($childHandles)) {
32
  $ignoreChild = (isset($data['ignore_child']['scripts'][$data['row']['obj']->handle]) && $data['ignore_child']['scripts'][$data['row']['obj']->handle]);
33
  ?>
34
+ <div class="wpacu_dependency_notice_area">
35
+ <?php
36
+ if ($data['row']['obj']->handle === 'jquery-migrate') {
37
+ ?>
38
+ <em style="font-size: 85%;">Special Case: If jQuery Migrate is marked for unload (which often is good if you don't need it), its official "child" (as it's mentioned in the WordPress core), jQuery, will not be unloaded. However, if there are other JS scripts from the plugins or the theme that are linked to jQuery Migrate, then it's better to keep it loaded.</em>
39
+ <?php
40
+ }
41
+
42
+ // If not 'jquery-migrate' show it
43
+ // If it's 'jquery-migrate' and has more than one "child" (apart from jQuery) show it
44
+ $showDependencyNotice = ($data['row']['obj']->handle === 'jquery-migrate' && count($childHandles) > 1) || ($data['row']['obj']->handle !== 'jquery-migrate');
45
+
46
+ if ($showDependencyNotice) {
47
+ ?>
48
+ <em style="font-size: 85%;">
49
+ <span style="color: #0073aa; width: 19px; height: 19px; vertical-align: middle;" class="dashicons dashicons-info"></span>
50
+ There are JS "children" files depending on this file. By unloading it, the following will also be unloaded:
51
+ <span style="color: green; font-weight: 600;">
52
+ <?php echo implode('<span style="color: black;">,</span> ', $childHandles); ?>
53
+ </span>
54
+ </em>
55
+ <div class="wpacu_hide_if_handle_row_contracted">
56
+ <label for="script_<?php echo $data['row']['obj']->handle; ?>_ignore_children">
57
+ &#10230; <input id="script_<?php echo $data['row']['obj']->handle; ?>_ignore_children"
58
+ type="checkbox"
59
+ <?php if ($ignoreChild) { ?>checked="checked"<?php } ?>
60
+ name="wpacu_ignore_child[scripts][<?php echo $data['row']['obj']->handle; ?>]"
61
+ value="1" /> <small><?php _e('Ignore dependency rule and keep the "children" loaded', 'wp-asset-clean-up'); ?></small>
62
+ </label>
63
+ </div>
64
+ <?php
65
+ }
66
+ ?>
67
+ </div>
68
+ <?php
69
  }
templates/meta-box-loaded-assets/_hardcoded/_asset-script-single-row-hardcoded/_source.php CHANGED
@@ -17,6 +17,19 @@ if (isset($data['row']['obj']->src, $data['row']['obj']->srcHref) && $data['row'
17
  $isExternalSrc = false;
18
  }
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  $relSrc = str_replace(site_url(), '', $data['row']['obj']->src);
21
 
22
  if (isset($data['row']['obj']->baseUrl)) {
@@ -26,7 +39,7 @@ if (isset($data['row']['obj']->src, $data['row']['obj']->srcHref) && $data['row'
26
  <div class="wpacu-source-row">
27
  <?php _e( 'Source:', 'wp-asset-clean-up' ); ?>
28
  <a target="_blank"
29
- style="color: green;" <?php if ( $isExternalSrc ) { ?> data-wpacu-external-source="<?php echo $data['row']['obj']->srcHref; ?>" <?php } ?>
30
  href="<?php echo $data['row']['obj']->src; ?>"><?php echo $relSrc; ?></a>
31
  <?php if ( $isExternalSrc ) { ?><span data-wpacu-external-source-status></span><?php } ?>
32
  </div>
17
  $isExternalSrc = false;
18
  }
19
 
20
+ $srcHref = $data['row']['obj']->srcHref;
21
+
22
+ // If the source starts with ../ mark it as external to be checked via the AJAX call (special case)
23
+ if (strpos($data['row']['obj']->srcHref, '../') === 0) {
24
+ $currentPageUrl = \WpAssetCleanUp\Misc::getCurrentPageUrl();
25
+ $currentPageUrl = trim($currentPageUrl, '/');
26
+
27
+ $srcHref = $currentPageUrl . '/'. $data['row']['obj']->srcHref;
28
+
29
+ $isExternalSrc = true; // simulation
30
+ }
31
+
32
+
33
  $relSrc = str_replace(site_url(), '', $data['row']['obj']->src);
34
 
35
  if (isset($data['row']['obj']->baseUrl)) {
39
  <div class="wpacu-source-row">
40
  <?php _e( 'Source:', 'wp-asset-clean-up' ); ?>
41
  <a target="_blank"
42
+ style="color: green;" <?php if ( $isExternalSrc ) { ?> data-wpacu-external-source="<?php echo $srcHref; ?>" <?php } ?>
43
  href="<?php echo $data['row']['obj']->src; ?>"><?php echo $relSrc; ?></a>
44
  <?php if ( $isExternalSrc ) { ?><span data-wpacu-external-source-status></span><?php } ?>
45
  </div>
templates/meta-box-loaded-assets/_hardcoded/_asset-style-single-row-hardcoded/_source.php CHANGED
@@ -16,6 +16,18 @@ if (isset($data['row']['obj']->src, $data['row']['obj']->srcHref) && $data['row'
16
  $isExternalSrc = false;
17
  }
18
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  $relSrc = str_replace(site_url(), '', $data['row']['obj']->src);
20
 
21
  if (isset($data['row']['obj']->baseUrl)) {
@@ -25,7 +37,7 @@ if (isset($data['row']['obj']->src, $data['row']['obj']->srcHref) && $data['row'
25
  <div class="wpacu-source-row">
26
  <?php _e( 'Source:', 'wp-asset-clean-up' ); ?>
27
  <a target="_blank"
28
- style="color: green;" <?php if ( $isExternalSrc ) { ?> data-wpacu-external-source="<?php echo $data['row']['obj']->srcHref; ?>" <?php } ?>
29
  href="<?php echo $data['row']['obj']->src; ?>"><?php echo $relSrc; ?></a>
30
  <?php if ( $isExternalSrc ) { ?><span data-wpacu-external-source-status></span><?php } ?>
31
  </div>
16
  $isExternalSrc = false;
17
  }
18
 
19
+ $srcHref = $data['row']['obj']->srcHref;
20
+
21
+ // If the source starts with ../ mark it as external to be checked via the AJAX call (special case)
22
+ if (strpos($data['row']['obj']->srcHref, '../') === 0) {
23
+ $currentPageUrl = \WpAssetCleanUp\Misc::getCurrentPageUrl();
24
+ $currentPageUrl = trim($currentPageUrl, '/');
25
+
26
+ $srcHref = $currentPageUrl . '/'. $data['row']['obj']->srcHref;
27
+
28
+ $isExternalSrc = true; // simulation
29
+ }
30
+
31
  $relSrc = str_replace(site_url(), '', $data['row']['obj']->src);
32
 
33
  if (isset($data['row']['obj']->baseUrl)) {
37
  <div class="wpacu-source-row">
38
  <?php _e( 'Source:', 'wp-asset-clean-up' ); ?>
39
  <a target="_blank"
40
+ style="color: green;" <?php if ( $isExternalSrc ) { ?> data-wpacu-external-source="<?php echo $srcHref; ?>" <?php } ?>
41
  href="<?php echo $data['row']['obj']->src; ?>"><?php echo $relSrc; ?></a>
42
  <?php if ( $isExternalSrc ) { ?><span data-wpacu-external-source-status></span><?php } ?>
43
  </div>
templates/meta-box-loaded.php CHANGED
@@ -148,6 +148,13 @@ if ($data['plugin_settings']['assets_list_layout'] === 'by-loaded-unloaded') {
148
  $data['page_unload_text'] = __('Unload on this page', 'wp-asset-clean-up');
149
  wp_cache_set('wpacu_data_page_unload_text', $data['page_unload_text']);
150
 
 
 
 
 
 
 
 
151
  // Assets List Layout - added here to convenience - to avoid going to "Settings"
152
  // it could make debugging faster
153
  ob_start();
148
  $data['page_unload_text'] = __('Unload on this page', 'wp-asset-clean-up');
149
  wp_cache_set('wpacu_data_page_unload_text', $data['page_unload_text']);
150
 
151
+ if (is_singular()) {
152
+ global $post;
153
+ ?>
154
+ <input type="hidden" name="wpacu_is_singular_page" value="<?php echo $post->ID; ?>" />
155
+ <?php
156
+ }
157
+
158
  // Assets List Layout - added here to convenience - to avoid going to "Settings"
159
  // it could make debugging faster
160
  ob_start();
wpacu-load.php CHANGED
@@ -21,13 +21,15 @@ function includeWpAssetCleanUpClassesAutoload($class)
21
 
22
  $pathToClass = WPACU_PLUGIN_CLASSES_PATH.$classFilter.'.php';
23
 
24
- if (file_exists($pathToClass)) {
25
  include_once $pathToClass;
26
  }
27
  }
28
 
29
  spl_autoload_register('includeWpAssetCleanUpClassesAutoload');
30
 
 
 
31
  // Main Class
32
  \WpAssetCleanUp\Main::instance();
33
 
@@ -45,9 +47,6 @@ $wpacuOwnAssets->init();
45
  $wpacuUpdate = new \WpAssetCleanUp\Update;
46
  $wpacuUpdate->init();
47
 
48
- // Various functions
49
- new \WpAssetCleanUp\Misc;
50
-
51
  // Menu
52
  new \WpAssetCleanUp\Menu;
53
 
21
 
22
  $pathToClass = WPACU_PLUGIN_CLASSES_PATH.$classFilter.'.php';
23
 
24
+ if (is_file($pathToClass)) {
25
  include_once $pathToClass;
26
  }
27
  }
28
 
29
  spl_autoload_register('includeWpAssetCleanUpClassesAutoload');
30
 
31
+ \WpAssetCleanUp\ObjectCache::wpacu_cache_init();
32
+
33
  // Main Class
34
  \WpAssetCleanUp\Main::instance();
35
 
47
  $wpacuUpdate = new \WpAssetCleanUp\Update;
48
  $wpacuUpdate->init();
49
 
 
 
 
50
  // Menu
51
  new \WpAssetCleanUp\Menu;
52
 
wpacu.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  * Plugin Name: Asset CleanUp: Page Speed Booster
4
  * Plugin URI: https://wordpress.org/plugins/wp-asset-clean-up/
5
- * Version: 1.3.6.1
6
  * Description: Unload Chosen Scripts & Styles from Posts/Pages to reduce HTTP Requests, Combine/Minify CSS/JS files
7
  * Author: Gabriel Livan
8
  * Author URI: http://gabelivan.com/
@@ -12,7 +12,7 @@
12
 
13
  // Is the Pro version triggered before the Lite one and are both plugins active?
14
  if (! defined('WPACU_PLUGIN_VERSION')) {
15
- define('WPACU_PLUGIN_VERSION', '1.3.6.1');
16
  }
17
 
18
  // Exit if accessed directly
2
  /*
3
  * Plugin Name: Asset CleanUp: Page Speed Booster
4
  * Plugin URI: https://wordpress.org/plugins/wp-asset-clean-up/
5
+ * Version: 1.3.6.2
6
  * Description: Unload Chosen Scripts & Styles from Posts/Pages to reduce HTTP Requests, Combine/Minify CSS/JS files
7
  * Author: Gabriel Livan
8
  * Author URI: http://gabelivan.com/
12
 
13
  // Is the Pro version triggered before the Lite one and are both plugins active?
14
  if (! defined('WPACU_PLUGIN_VERSION')) {
15
+ define('WPACU_PLUGIN_VERSION', '1.3.6.2');
16
  }
17
 
18
  // Exit if accessed directly