Файловый менеджер - Редактировать - /home/infrafs/INFRABIKEIT/wp-content/plugins/autoptimize.zip
Назад
PK ��3\)�=g� � readme.txtnu �[��� === Autoptimize === Contributors: futtta, optimizingmatters, zytzagoo, turl Tags: optimize, performance, images, core web vitals, pagespeed Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/ Requires at least: 5.3 Tested up to: 6.6 Requires PHP: 5.6 Stable tag: 3.1.11 Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-load), HTML and Google Fonts, asyncing JS, removing emoji cruft and more. == Description == Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default but can also inline critical CSS and defer the aggregated full CSS, moves and defers scripts to the footer and minifies HTML. You can optimize and lazy-load images (with support for WebP and AVIF formats), optimize Google Fonts, async non-aggregated JavaScript, remove WordPress core emoji cruft and more. As such it can improve your site's performance even when already on HTTP/2! There is extensive API available to enable you to tailor Autoptimize to each and every site's specific needs. If you think performance indeed is important, you should at least consider one of the many free page caching plugins (e.g. [Speed Booster pack](https://wordpress.org/plugins/speed-booster-pack/) or [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler)) to complement Autoptimize or even [consider Autoptimize Pro](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=aopro) which not only has page caching but also image optimization, CDN, critical CSS and more! > <strong>Autoptimize Pro</strong><br> > [Autoptimize Pro is a premium Power-Up](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=aopro), adding image optimization, CDN, page caching, automatic critical CSS rules and extra “booster” options, all in one handy subscription to [make your site even faster!](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=aopro)! > <strong>Premium Support</strong><br> > We provide great [Premium Support and Web Performance Optimization services](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro) with Accelera, check out our offering on [https://accelerawp.com/](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro)! (Speed-surfing image under creative commons [by LL Twistiti](https://www.flickr.com/photos/twistiti/818552808/)) == Installation == Just install from your WordPress "Plugins > Add New" screen and all will be well. Manual installation is very straightforward as well: 1. Upload the zip file and unzip it in the `/wp-content/plugins/` directory 1. Activate the plugin through the 'Plugins' menu in WordPress 1. Go to `Settings > Autoptimize` and enable the options you want. Generally this means "Optimize HTML/ CSS/ JavaScript". == Frequently Asked Questions == = What does the plugin do to help speed up my site? = It minifies all scripts and styles and configures your webserver to compresses them with good expires headers. JavaScript be default will be made non-render-blocking and CSS can be too by adding critical CSS. You can configure it to combine (aggregate) CSS & JS-files, in which case styles are moved to the page head, and scripts to the footer. It also minifies the HTML code and can also optimize images and Google Fonts, making your page really lightweight. = But I'm on HTTP/2, so I don't need Autoptimize? = HTTP/2 is a great step forward for sure, reducing the impact of multiple requests from the same server significantly by using the same connection to perform several concurrent requests and for that reason on new installations Autoptimize will not aggregate CSS and JS files any more. That being said, [concatenation of CSS/ JS can still make a lot of sense](http://engineering.khanacademy.org/posts/js-packaging-http2.htm), as described in [this css-tricks.com article](https://css-tricks.com/http2-real-world-performance-test-analysis/) and this [blogpost from one of the Ebay engineers](http://calendar.perfplanet.com/2015/packaging-for-performance/). The conclusion; configure, test, reconfigure, retest, tweak and look what works best in your context. Maybe it's just HTTP/2, maybe it's HTTP/2 + aggregation and minification, maybe it's HTTP/2 + minification (which AO can do as well, simply untick the "aggregate JS-files" and/ or "aggregate CSS-files" options). And Autoptimize can do a lot more then "just" optimizing your JS & CSS off course ;-) = Will this work with my blog? = Although Autoptimize comes without any warranties, it will in general work flawlessly if you configure it correctly. See "Troubleshooting" below for info on how to configure in case of problems. If you want you can [test Autoptimize on a new free dummy site, courtesy of tastewp.com](https://demo.tastewp.com/autoptimize). = Why is jquery.min.js not optimized when aggregating JavaScript? = Starting from AO 2.1 WordPress core's jquery.min.js is not optimized for the simple reason a lot of popular plugins inject inline JS that is not aggregated either (due to possible cache size issues with unique code in inline JS) which relies on jquery being available, so excluding jquery.min.js ensures that most sites will work out of the box. If you want optimize jquery as well, you can remove it from the JS optimization exclusion-list (you might have to enable "also aggregate inline JS" as well or switch to "force JS in head"). = Why is Autoptimized JS render blocking? = This happens when aggregating JavaSCript and ticking the "force in head" option or when not aggregating and not deferring. Consider changing settings. = Why is the autoptimized CSS still called out as render blocking? = With the default Autoptimize configuration the CSS is linked in the head, which is a safe default but has Google PageSpeed Insights complaining. You can look into "inline all CSS" (easy) or "inline and defer CSS" (better) which are explained in this FAQ as well. = What is the use of "inline and defer CSS"? = CSS in general should go in the head of the document. Recently a.o. Google started promoting deferring non-essential CSS, while inlining those styles needed to build the page above the fold. This is especially important to render pages as quickly as possible on mobile devices. As from Autoptimize 1.9.0 this is easy; select "inline and defer CSS", paste the block of "above the fold CSS" in the input field (text area) and you're good to go! = But how can one find out what the "above the fold CSS" is? = There's no easy solution for that as "above the fold" depends on where the fold is, which in turn depends on screensize. There are some tools available however, which try to identify just what is "above the fold". [This list of tools](https://github.com/addyosmani/above-the-fold-css-tools) is a great starting point. The [Sitelocity critical CSS generator](https://www.sitelocity.com/critical-path-css-generator) and [Jonas Ohlsson's criticalpathcssgenerator](http://jonassebastianohlsson.com/criticalpathcssgenerator/) are nice basic solutions and [http://criticalcss.com/](http://misc.optimizingmatters.com/partners/?from=faq&partner=critcss) is a premium solution by the same Jonas Ohlsson. Alternatively [this bookmarklet](https://gist.github.com/PaulKinlan/6284142) (Chrome-only) can be helpful as well. = Or should you inline all CSS? = The short answer: probably not. Although inlining all CSS will make the CSS non-render blocking, it will result in your base HTML-page getting significantly bigger thus requiring more "roundtrip times". Moreover when considering multiple pages being requested in a browsing session the inline CSS is sent over each time, whereas when not inlined it would be served from cache. Finally the inlined CSS will push the meta-tags in the HTML down to a position where Facebook or Whatsapp might not look for it any more, breaking e.g. thumbnails when sharing on these platforms. = My cache is getting huge, doesn't Autoptimize purge the cache? = Autoptimize does not have its proper cache purging mechanism, as this could remove optimized CSS/JS which is still referred to in other caches, which would break your site. Moreover a fast growing cache is an indication of [other problems you should avoid](http://blog.futtta.be/2016/09/15/autoptimize-cache-size-the-canary-in-the-coal-mine/). Instead you can keep the cache size at an acceptable level by either: * disactivating the "aggregate inline JS" and/ or "aggregate inline CSS" options * excluding JS-variables (or sometimes CSS-selectors) that change on a per page (or per pageload) basis. You can read how you can do that [in this blogpost](http://blog.futtta.be/2014/03/19/how-to-keep-autoptimizes-cache-size-under-control-and-improve-visitor-experience/). Despite above objections, there are 3rd party solutions to automatically purge the AO cache, e.g. using [this code](https://wordpress.org/support/topic/contribution-autoptimize-cache-size-under-control-by-schedule-auto-cache-purge/) or [this plugin](https://wordpress.org/plugins/bi-clean-cache/), but for reasons above these are to be used only if you really know what you're doing. = "Clear cache" doesn't seem to work? = When clicking the "Delete Cache" link in the Autoptimize dropdown in the admin toolbar, you might to get a "Your cache might not have been purged successfully". In that case go to Autoptimizes setting page and click the "Save changes & clear cache"-button. Moreover don't worry if your cache never is down to 0 files/ 0KB, as Autoptimize (as from version 2.2) will automatically preload the cache immediately after it has been cleared to speed further minification significantly up. = My site looks broken when I purge Autoptimize's cache! = When clearing AO's cache, no page cache should contain pages (HTML) that refers to the removed optimized CSS/ JS. Although for that purpose there is integration between Autoptimize and some page caches, this integration does not cover 100% of setups so you might need to purge your page cache manually. = Can I still use Cloudflare's Rocket Loader? = Cloudflare Rocket Loader is a pretty advanced but invasive way to make JavaScript non-render-blocking, which [Cloudflare still considers Beta](https://wordpress.org/support/topic/rocket-loader-breaking-onload-js-on-linked-css/#post-9263738). Sometimes Autoptimize & Rocket Loader work together, sometimes they don't. The best approach is to disable Rocket Loader, configure Autoptimize and re-enable Rocket Loader (if you think it can help) after that and test if everything still works. At the moment (June 2017) it seems RocketLoader might break AO's "inline & defer CSS", which is based on [Filamentgroup’s loadCSS](https://github.com/filamentgroup/loadCSS), resulting in the deferred CSS not loading. = I tried Autoptimize but my Google Pagespeed Scored barely improved = Autoptimize is not a simple "fix my Pagespeed-problems" plugin; it "only" aggregates & minifies (local) JS & CSS and images and allows for some nice extra's as removing Google Fonts and deferring the loading of the CSS. As such Autoptimize will allow you to improve your performance (load time measured in seconds) and will probably also help you tackle some specific Pagespeed warnings. If you want to improve further, you will probably also have to look into e.g. page caching and your webserver configuration, which will improve real performance (again, load time as measured by e.g. https://webpagetest.org) and your "performance best practice" pagespeed ratings. = What can I do with the API? = A whole lot; there are filters you can use to conditionally disable Autoptimize per request, to change the CSS- and JS-excludes, to change the limit for CSS background-images to be inlined in the CSS, to define what JS-files are moved behind the aggregated one, to change the defer-attribute on the aggregated JS script-tag, ... There are examples for some filters in autoptimize_helper.php_example and in this FAQ. = How does CDN work? = Starting from version 1.7.0, CDN is activated upon entering the CDN blog root directory (e.g. http://cdn.example.net/wordpress/). If that URL is present, it will used for all Autoptimize-generated files (i.e. aggregated CSS and JS), including background-images in the CSS (when not using data-uri's). If you want your uploaded images to be on the CDN as well, you can change the upload_url_path in your WordPress configuration (/wp-admin/options.php) to the target CDN upload directory (e.g. http://cdn.example.net/wordpress/wp-content/uploads/). Do take into consideration this only works for images uploaded from that point onwards, not for images that already were uploaded. Thanks to [BeautyPirate for the tip](http://wordpress.org/support/topic/please-don%c2%b4t-remove-cdn?replies=15#post-4720048)! = Why aren't my fonts put on the CDN as well? = Autoptimize supports this, but it is not enabled by default because [non-local fonts might require some extra configuration](http://davidwalsh.name/cdn-fonts). But if you have your cross-origin request policy in order, you can tell Autoptimize to put your fonts on the CDN by hooking into the API, setting `autoptimize_filter_css_fonts_cdn` to `true` this way; `add_filter( 'autoptimize_filter_css_fonts_cdn', '__return_true' );` = I'm using Cloudflare, what should I enter as CDN root directory = Nothing, when on Cloudflare your autoptimized CSS/ JS is on the Cloudflare's CDN automatically. = How can I force the aggregated files to be static CSS or JS instead of PHP? = If your webserver is properly configured to handle compression (gzip or deflate) and cache expiry (expires and cache-control with sufficient cacheability), you don't need Autoptimize to handle that for you. In that case you can check the "Save aggregated script/css as static files?"-option, which will force Autoptimize to save the aggregated files as .css and .js-files (meaning no PHP is needed to serve these files). This setting is default as of Autoptimize 1.8. = How does "exclude from optimizing" work? = Both CSS and JS optimization can skip code from being aggregated and minimized by adding "identifiers" to the comma-separated exclusion list. The exact identifier string to use can be determined this way: * if you want to exclude a specific file, e.g. wp-content/plugins/funkyplugin/css/style.css, you could simply exclude "funkyplugin/css/style.css" * if you want to exclude all files of a specific plugin, e.g. wp-content/plugins/funkyplugin/js/*, you can exclude for example "funkyplugin/js/" or "plugins/funkyplugin" * if you want to exclude inline code, you'll have to find a specific, unique string in that block of code and add that to the exclusion list. Example: to exclude `<script>funky_data='Won\'t you take me to, Funky Town'</script>`, the identifier is "funky_data". = Troubleshooting Autoptimize = Have a look at the troubleshooitng instructions at https://blog.futtta.be/2022/05/05/what-to-do-when-autoptimize-breaks-your-site/ = I excluded files but they are still being autoptimized? = AO minifies excluded JS/ CSS if the filename indicates the file is not minified yet. As of AO 2.5 you can disable this on the "JS, CSS & HTML"-tab under misc. options by unticking "minify excluded files". = Help, I have a blank page or an internal server error after enabling Autoptimize!! = Make sure you're not running other HTML, CSS or JS minification plugins (BWP minify, WP minify, ...) simultaneously with Autoptimize or disable that functionality your page caching plugin (W3 Total Cache, WP Fastest Cache, ...). Try enabling only CSS or only JS optimization to see which one causes the server error and follow the generic troubleshooting steps to find a workaround. = But I still have blank autoptimized CSS or JS-files! = If you are running Apache, the .htaccess file written by Autoptimize can in some cases conflict with the AllowOverrides settings of your Apache configuration (as is the case with the default configuration of some Ubuntu installations), which results in "internal server errors" on the autoptimize CSS- and JS-files. This can be solved by [setting AllowOverrides to All](http://httpd.apache.org/docs/2.4/mod/core.html#allowoverride). = Can't log in on domain mapped multisites = Domain mapped multisites require Autoptimize to be initialized at a different WordPress action, add this line of code to your wp-config.php to make it so to hook into `setup_theme` for example: `define( 'AUTOPTIMIZE_SETUP_INITHOOK', 'setup_theme' );` = I get no error, but my pages are not optimized at all? = Autoptimize does a number of checks before actually optimizing. When one of the following is true, your pages won't be optimized: * when in the customizer * if there is no opening `<html` tag * if there is `<xsl:stylesheet` in the response (indicating the output is not HTML but XML) * if there is `<html amp` in the response (as AMP-pages are optimized already) * if the output is an RSS-feed (is_feed() function) * if the output is a WordPress administration page (is_admin() function) * if the page is requested with ?ao_noptimize=1 appended to the URL * if code hooks into Autoptimize to disable optimization (see topic on Visual Composer) * if other plugins use the output buffer in an incompatible manner (disable other plugins selectively to identify the culprit) = Visual Composer, Beaver Builder and similar page builder solutions are broken!! = Disable the option to have Autoptimize active for logged on users and go crazy dragging and dropping ;-) = Help, my shop checkout/ payment don't work!! = Disable the option to optimize cart/ checkout pages (works for WooCommerce, Easy Digital Downloads and WP eCommerce). = Revolution Slider is broken! = Make sure `js/jquery/jquery.min.js` is in the comma-separated list of JS optimization exclusions (this is excluded in the default configuration). = I'm getting "jQuery is not defined" errors = In that case you have un-aggregated JavaScript that requires jQuery to be loaded, so you'll have to add `js/jquery/jquery.min.js` to the comma-separated list of JS optimization exclusions. = I use NextGen Galleries and a lot of JS is not aggregated/ minified? = NextGen Galleries does some nifty stuff to add JavaScript. In order for Autoptimize to be able to aggregate that, you can either disable Nextgen Gallery's resourced manage with this code snippet `add_filter( 'run_ngg_resource_manager', '__return_false' );` or you can tell Autoptimize to initialize earlier, by adding this to your wp-config.php: `define("AUTOPTIMIZE_INIT_EARLIER","true");` = What is noptimize? = Starting with version 1.6.6 Autoptimize excludes everything inside noptimize tags, e.g.: `<!--noptimize--><script>alert('this will not get autoptimized');</script><!--/noptimize-->` You can do this in your page/ post content, in widgets and in your theme files (consider creating [a child theme](http://codex.wordpress.org/Child_Themes) to avoid your work being overwritten by theme updates). = Can I change the directory & filename of cached autoptimize files? = Yes, if you want to serve files from e.g. /wp-content/resources/aggregated_12345.css instead of the default /wp-content/cache/autoptimize/autoptimize_12345.css, then add this to wp-config.php: ` define('AUTOPTIMIZE_CACHE_CHILD_DIR','/resources/'); define('AUTOPTIMIZE_CACHEFILE_PREFIX','aggregated_'); ` = Does this work with non-default WP_CONTENT_URL ? = No, Autoptimize does not support a non-default WP_CONTENT_URL out-of-the-box, but this can be accomplished with a couple of lines of code hooking into Autoptimize's API. = Can the generated JS/ CSS be pre-gzipped? = Yes, but this is off by default. You can enable this by passing ´true´ to ´autoptimize_filter_cache_create_static_gzip´. You'll obviously still have to configure your webserver to use these files instead of the non-gzipped ones to avoid the overhead of on-the-fly compression. = What does "remove emojis" do? = This new option in Autoptimize 2.3 removes the inline CSS, inline JS and linked JS-file added by WordPress core. As such is can have a small positive impact on your site's performance. = Is "remove query strings" useful? = Although some online performance assessment tools will single out "query strings for static files" as an issue for performance, in general the impact of these is almost non-existant. As such Autoptimize, since version 2.3, allows you to have the query string (or more precisely the "ver"-parameter) removed, but ticking "remove query strings from static resources" will have little or no impact of on your site's performance as measured in (milli-)seconds. = (How) should I optimize Google Fonts? = Google Fonts are typically loaded by a "render blocking" linked CSS-file. If you have a theme and plugins that use Google Fonts, you might end up with multiple such CSS-files. Autoptimize (since version 2.3) now let's you lessen the impact of Google Fonts by either removing them alltogether or by optimizing the way they are loaded. There are two optimization-flavors; the first one is "combine and link", which replaces all requests for Google Fonts into one request, which will still be render-blocking but will allow the fonts to be loaded immediately (meaning you won't see fonts change while the page is loading). The alternative is "combine and load async" which uses JavaScript to load the fonts in a non-render blocking manner but which might cause a "flash of unstyled text". = Should I use "preconnect" = Preconnect is a somewhat advanced feature to instruct browsers ([if they support it](https://caniuse.com/#feat=link-rel-preconnect)) to make a connection to specific domains even if the connection is not immediately needed. This can be used e.g. to lessen the impact of 3rd party resources on HTTPS (as DNS-request, TCP-connection and SSL/TLS negotiation are executed early). Use with care, as preconnecting to too many domains can be counter-productive. = When can('t) I async JS? = JavaScript files that are not autoptimized (because they were excluded or because they are hosted elsewhere) are typically render-blocking. By adding them in the comma-separated "async JS" field, Autoptimize will add the async flag causing the browser to load those files asynchronously (i.e. non-render blocking). This can however break your site (page), e.g. if you async "js/jquery/jquery.min.js" you will very likely get "jQuery is not defined"-errors. Use with care. = How does image optimization work? = When image optimization is on, Autoptimize will look for png, gif, jpeg (.jpg) files in image tags and in your CSS files that are loaded from your own domain and change the src (source) to the ShortPixel CDN for those. Important: this can only work for publicly available images, otherwise the image optimization proxy will not be able to get the image to optimize it, so firewalls or proxies or password protection or even hotlinking-prevention might break image optimization. = Can I use image optimization for my intranet/ protected site? = No; Image optimization depends on the ability of the external image optimization service to fetch the original image from your site, optimize it and save it on the CDN. If you images cannot be downloaded by anonymous visitors (due to firewall/ proxy/ password protection/ hotlinking-protection), image optimization will not work. = Where can I get more info on image optimization? = Have a look at [Shortpixel's FAQ](https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn). = Can I disable AO listening to page cache purges? = As from AO 2.4 AO "listens" to page cache purges to clear its own cache. You can disable this behavior with this filter; ` add_filter('autoptimize_filter_main_hookpagecachepurge','__return_false');` = Some of the non-ASCII characters get lost after optimization = By default AO uses non multibyte-safe string methods, but if your PHP has the mbstring extension you can enable multibyte-safe string functions with this filter; ` add_filter('autoptimize_filter_main_use_mbstring', '__return_true');` = I can't get Critical CSS working = Check [the FAQ on the (legacy) "power-up" here](https://wordpress.org/plugins/autoptimize-criticalcss/#faq), this info will be integrated in this FAQ at a later date. = Do I still need the Critical CSS power-up when I have Autoptimize 2.7 or higher? = No, the Critical CSS power-up is not needed any more, all functionality (and many fixes/ improvements) are now part of Autoptimize. = What does "enable 404 fallbacks" do? Why would I need this? = Autoptimize caches aggregated & optimized CSS/ JS and links to those cached files are stored in the HTML, which will be stored in a page cache (which can be a plugin, can be at host level, can be at 3rd party, in the Google cache, in a browser). If there is HTML in a page cache that links to Autoptimized CSS/ JS that has been removed in the mean time (when the cache was cleared) then the page from cache will not look/ work as expected as the CSS or JS were not found (a 404 error). This setting aims to prevent things from breaking by serving "fallback" CSS or JS. The fallback-files are copies of the first Autoptimized CSS & JS files created after the cache was emptied and as such will based on the homepage. This means that the CSS/ JS migth not apply 100% on other pages, but at least the impact of missing CSS/ JS will be lessened (often significantly). When the option is enabled, Autoptimize adds an `ErrorDocument 404` to the .htaccess (as used by Apache) and will also hook into WordPress core `template_redirect` to capture 404's handled by Wordpress. When using NGINX something like below should work (I'm not an NGINX specialist, but it does work for me); ` location ~* /wp-content/cache/autoptimize/.*\.(js|css)$ { try_files $uri $uri/ /wp-content/autoptimize_404_handler.php; }` And this a nice alternative approach (provided by fboylovesyou); `location ~* /wp-content/cache/autoptimize/.*\.(css)$ { try_files $uri $uri/ /wp-content/cache/autoptimize/css/autoptimize_fallback.css; } location ~* /wp-content/cache/autoptimize/.*\.(js)$ { try_files $uri $uri/ /wp-content/cache/autoptimize/js/autoptimize_fallback.js; }` = What open source software/ projects are used in Autoptimize? = The following great open source projects are used in Autoptimize in some form or another: * [Mr Clay's Minify](https://github.com/mrclay/minify/) for JS & HTML minification * [YUI CSS compressor PHP Port](https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port) for CSS minification * [Lazysizes](https://github.com/aFarkas/lazysizes) for lazyload * [Persist Admin Notices Dismissal](https://github.com/w3guy/persist-admin-notices-dismissal) for notices in the administration screens * [Plugin Update Checker](https://github.com/YahnisElsts/plugin-update-checker/) for automated updates from Github for the beta version * [LoadCSS](https://github.com/filamentgroup/loadCSS) for deferring full CSS * [jQuery cookie](https://github.com/carhartl/jquery-cookie) to store the "futtta about" category selection in a cookie * [jQuery tablesorter](https://github.com/christianbach/tablesorter) for the critical CSS rules/ jobs display * [jQuery unslider](https://github.com/idiot/unslider/) for the mini-slider in the top right corner on the main settings page (repo gone) * [JavaScript-md5](https://github.com/blueimp/JavaScript-MD5) for critical CSS rules editing * [Speed Booster Pack](https://wordpress.org/plugins/speed-booster-pack/) for advanced JS deferring * [Disable Remove Google Fonts](https://wordpress.org/plugins/disable-remove-google-fonts/) for additional Google Font removal = Where can I get help? = You can get help on the [wordpress.org support forum](http://wordpress.org/support/plugin/autoptimize). If you are 100% sure this your problem cannot be solved using Autoptimize configuration and that you in fact discovered a bug in the code, you can [create an issue on GitHub](https://github.com/futtta/autoptimize/issues). If you're looking for premium support, check out our [Autoptimize Pro Support and Web Performance Optimization services](http://autoptimize.com/). = I want out, how should I remove Autoptimize? = * Disable the plugin (this will remove options and cache) * Remove the plugin * Clear any cache that might still have pages which reference Autoptimized CSS/JS (e.g. of a page caching plugin such as WP Super Cache) = How can I help/ contribute? = Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and code away! == Changelog == = 3.1.12 = * image optimization: improvements to the favicon regex * javascript optimization: integrate most recent version of jsmin.php * critical CSS: improve blocklist (url/ paths that should not be added to the job queue) * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.11 = * code quality improvements see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.10 = * improvement: with "don't aggregate but defer" and "also defer inline JS" on, also defer JS that had the async flag to avoid the (previously) asynced JS from executing before the inline JS has ran. * improvement: show option to disable the default on "compatibility logic". * fix for regression in 3.1.9 which caused JetPack Image optimization not working even if image optimization was off in AO. * API: some extra hooks in critical CSS to enable others (and AOPro) to act on changes in critical CSS rules * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.9 = * improvement: activate JS, CSS & HTML optimization upon plugin activation (hat tip to Adam Silverstein (developer relations engineer at Google)) * improvement: also defer asynced JS (to ensure execution order remains intact; asynced JS should not execute before deferred inline JS which it might depend upon) * improvement: exclude images from being lazyloaded if they have fetchpriority attribute set to high (as done by WordPress core since 6.3) * bugfix: disable spellcheck on CSS textarea's (above the fold CSS/ critical CSS) which in some cases caused browser issues * add tab to explain Autoptimize Pro. * confirmed working with WordPress 6.4 (beta 3) * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.8.1 = * urgent fix for PHP error, sorry about that! = 3.1.8 = * Images: improve optmization logic for background images * Critical CSS: don't trigger custom_post rule if not is_singular + adding debug logging for rule selection * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.7 = * security: improve validation (import) and sanitization (output) of critical CSS rules, to fix a medium severity Admin+ Stored Cross-Site Scripting vulnerability as reported by WP Scan Security. = 3.1.6 = * CSS: removing trailing slashes in <link tags for more W3 HTML validation love * Extra: also dequeue WooCommerce block CSS if "remove WordPress block CSS" option is active * imgopt: also act on non-aggregated inline CSS * imgopt: added logic to warn users if Shortpixel can't reach their site * backend: AO toolbar JS/ CSS is finally minified as well. * explicitly disable optimization of login pages * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.5 = * improvements to JSMin by Robert Ehrenleitner (big thanks Robert!). * do not consider jquery.js as minified any more (WordPress now uses jquery.min.js by default and jquery.js is the unminified version). * fix for "undefined array key" PHP errors in autoptimizeCriticalCSSCron.php * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.4 = * Improvement: when all CSS is inlined, try doing so after SEO meta-tags (just before ld+json script tag which most SEO plugins add as last item on their list). * Img opt: also optimize images set in data-background and data-retina attributes (+ filter to easily add other attributes) * CSS opt: filter to enable AO to skip minification of calc formulas in CSS (as the CSS minifier on rare occasions breaks those) * Multiple other filters added * Some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.3 = * Multiple fixes for metabox LCP image preloads (thanks [Kishorchand](https://foxscribbler.com/) for notifying & providing a staging environment to debug on). * Fix in revslider compatibility (hat tip [Waqar Ahmed for reporting & helping out](https://wordpress.org/support/topic/issue-with-latest-version-of-slider-revolution/) ). * No image optimization or criticalcss attempts on localhost installations any more + notification of that fact if localhost detected. * Some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.2 = * Google Fonts: some more removal logic * fix for 404 fallback bug (hat tip to Asif for finding & reporting) * Some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.1.1 = * Quick workaround for an autoload conflict with JetFormBuilder (and maybe other Crocoblock plugins?) that causes a critical error on the AO settings page. = 3.1.1 = * images: when optimizing images and lazyloading is on, then by default do not set an LQIP (low quality image placeholder) any more (reason: it might *look* nice but it comes with a small-ish perf. penalty). This can be re-enabled by returning true to the `autoptimize_filter_imgopt_lazyload_dolqip` filter. * security: further improvements to critical CSS settings page (again with the great assistance of WPScan Security). * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta). = 3.1.0 = * new HTML sub-option: "minify inline CSS/ JS" (off by default). * new Misc option: permanently allow the "do not run compatibility logic" flag to be removed (which was set for users upgrading from AO 2.9.* to AO 3.0.* as the assumption was things were working anyway). * security: improvements to the critical CSS settings page to fix authenticated cross site scripting issues as reported by WPScan Security. * bugfix: "defer inline JS" of very large chunks of inline JS could cause server errors (PCRE crash actually) so not deferring if string is more then 200000 characters (filter available). * some other minor changes/ improvements/ hooks, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta) = 3.0.4 = * fix for "undefined array key ao_post_preload” on post/ page edit screens * fix for image optimization altering inline JS that contains an `<img` tag if lazyload is not active * improvements to exit survey * confirmed working with WordPress 6.0 = 3.0.3 = * fix for images being preloaded without this being configured when lazyload is on and per page/post settings are off. * ensure critical CSS schedule is always known. * when deferring non-aggregated JS, make the optimatization exclusions take the full script-tag into account instead of just the src URL. = 3.0.2 = * rollback automatic "minify inline CSS/ JS" which broke more then expected, this will come back as a separate default off option later and can now be enabled with a simple filter: `add_filter( 'autoptimize_html_minify_inline_js_css', '__return_true');` . * fix for "Call to undefined method autoptimizeOptionWrapper::delete_option()" in autoptimizeVersionUpdatesHandler.php = 3.0.1 = * fix for minification of inline script with type text/template breaking the template (e.g. ninja forms), hat tip to @bobsled. * fix for regression in import of CSS-files where e.g. fontawesome CSS was broken due to being escaped again with help of @bobsled, thanks man! = 3.0.0 = * fundamental change for new installations: by default Autoptimize will not aggregate JS/ CSS any more (HTTP/2 is ubiquitous and there are other advantages to not aggregating esp. re. inline JS/ CSS and dependancies) * new: no API needed any more to create manual critical CSS rules. * new: "Remove WordPress blocks CSS" option on the "Extra" tab to remove block- and global styles (and SVG). * new: compatibility logic for "edit with elementor", "revolution slider", for non-aggregated inline JS requiring jQuery even if not excluded (= auto-exclude of jQuery) and JS-heavy WordPress blocks (Gutenberg) * new: configure an image to be preloaded on a per page/ post basis for better LCP. * improvement: defer inline now also allowed if inline JS contains nonce or post_id. * improvement: settings export/ import on critical CSS tab now takes into account all Autoptimize settings, not just the critical CSS ones. * technical improvement: all criticalCSS classes were refactored, removing use of global variables. * technical improvement: automated unit tests on Travis-CI for PHP versions 7.2 to 8.1. * fix: stop Divi from clearing Autoptimize's cache [which is pretty counter-productive](https://blog.futtta.be/2018/11/17/warning-divi-purging-autoptimizes-cache/). * misc smaller fixes/ improvements, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta) = older = * see [https://plugins.svn.wordpress.org/autoptimize/tags/2.9.5.1/readme.txt](https://plugins.svn.wordpress.org/autoptimize/tags/2.9.5.1/readme.txt) PK ��3\v�;ZkF kF LICENSEnu �[��� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. PK ��3\�S S autoptimize_helper.php_examplenu �[��� <?php /* Plugin Name: Autoptimize Helper Plugin URI: http://blog.futtta.be/autoptimize Description: Autoptimize Helper contains some helper functions to make Autoptimize even more flexible Author: Frank Goossens (futtta) Version: 0.2 Author URI: http://blog.futtta.be/ */ /* autoptimize_filter_css_datauri_maxsize: change the threshold at which background images are turned into data uri's; @param $urisize: default size @return: your own preferred size */ // add_filter('autoptimize_filter_css_datauri_maxsize','my_ao_override_dataursize',10,1); function my_ao_override_dataursize($urisizeIn) { return 100000; } /* autoptimize_filter_css_datauri_exclude: exclude background images from being turned into data uri's; @param $imageexcl: default images excluded (empty) @return: comma-seperated list of images to exclude */ // add_filter('autoptimize_filter_css_datauri_exclude','my_ao_exclude_image',10,1); function my_ao_exclude_image($imageexcl) { return $imageexcl . ", adfreebutton.jpg, otherimage.png"; } /* autoptimize_filter_js_defer: change flag added to javascript @param $defer: default value, "" when forced in head, "defer " when not forced in head @return: new value */ // add_filter('autoptimize_filter_js_defer','my_ao_override_defer',10,1); function my_ao_override_defer($defer) { return $defer."async "; } /* autoptimize_filter_noptimize: stop autoptimize from optimizing, e.g. based on URL as in example @return: boolean, true or false */ // add_filter('autoptimize_filter_noptimize','my_ao_noptimize',10,1); function my_ao_noptimize( $flag_in ) { if (strpos($_SERVER['REQUEST_URI'],'no-autoptimize-now')!==false) { return true; } else { return $flag_in; } } /* autoptimize_filter_js_exclude; JS optimization exclude strings, as configured in admin page @param $exclude: comma-seperated list of exclude strings @return: comma-seperated list of exclude strings */ // add_filter('autoptimize_filter_js_exclude','my_ao_override_jsexclude',10,1); function my_ao_override_jsexclude($exclude) { return $exclude.", customize-support"; } /* autoptimize_filter_css_exclude: CSS optimization exclude strings, as configured in admin page @param $exclude: comma-seperated list of exclude strings @return: comma-seperated list of exclude strings */ // add_filter('autoptimize_filter_css_exclude','my_ao_override_cssexclude',10,1); function my_ao_override_cssexclude($exclude) { return $exclude.", recentcomments"; } /* autoptimize_filter_js_movelast: internal array of what script can be moved to the bottom of the HTML @param array $movelast @return: updated array */ // add_filter('autoptimize_filter_js_movelast','my_ao_override_movelast',10,1); function my_ao_override_movelast($movelast) { $movelast[]="console.log"; return $movelast; } /* autoptimize_filter_css_replacetag: where in the HTML is optimized CSS injected @param array $replacetag, containing the html-tag and the method (inject "before", "after" or "replace") @return array with updated values */ // add_filter('autoptimize_filter_css_replacetag','my_ao_override_css_replacetag',10,1); function my_ao_override_css_replacetag($replacetag) { return array("<head>","after"); } /* autoptimize_filter_js_replacetag: where in the HTML is optimized JS injected @param array $replacetag, containing the html-tag and the method (inject "before", "after" or "replace") @return array with updated values */ // add_filter('autoptimize_filter_js_replacetag','my_ao_override_js_replacetag',10,1); function my_ao_override_js_replacetag($replacetag) { return array("<injectjs />","replace"); } /* autoptimize_js_do_minify: do we want to minify? if set to false autoptimize effectively only aggregates, but does not minify @return: boolean true or false */ // add_filter('autoptimize_js_do_minify','my_ao_js_minify',10,1); function my_ao_js_minify() { return false; } /* autoptimize_css_do_minify: do we want to minify? if set to false autoptimize effectively only aggregates, but does not minify @return: boolean true or false */ // add_filter('autoptimize_css_do_minify','my_ao_css_minify',10,1); function my_ao_css_minify() { return false; } /* autoptimize_js_include_inline: do we want AO to also aggregate inline JS? @return: boolean true or false */ // add_filter('autoptimize_js_include_inline','my_ao_js_include_inline',10,1); function my_ao_js_include_inline() { return false; } /* autoptimize_css_include_inline: do we want AO to also aggregate inline CSS? @return: boolean true or false */ // add_filter('autoptimize_css_include_inline','my_ao_css_include_inline',10,1); function my_ao_css_include_inline() { return false; } /* autoptimize_filter_css_defer_inline: what CSS to inline when "defer and inline" is activated @param $inlined: string with above the fold CSS as configured in admin @return: updated string with above the fold CSS */ // add_filter('autoptimize_filter_css_defer_inline','my_ao_css_defer_inline',10,1); function my_ao_css_defer_inline($inlined) { return $inlined."h2,h1{color:red !important;}"; } /* autoptimize_filter_css_fonts_cdn: do we want to move fonts to the CDN-url as well @return: false (default) or true */ // add_filter('autoptimize_filter_css_fonts_cdn','my_css_cdnfont',10,0); function my_css_cdnfont(){ return true; } PK ��3\���b�i �i . classes/autoptimizeCriticalCSSSettingsAjax.phpnu �[��� <?php /** * Critical CSS settings AJAX logic. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeCriticalCSSSettingsAjax { /** * Critical CSS object. * * @var object */ protected $criticalcss; public function __construct() { $this->criticalcss = autoptimize()->criticalcss(); $this->run(); } public function run() { // add filters. add_action( 'wp_ajax_fetch_critcss', array( $this, 'critcss_fetch_callback' ) ); add_action( 'wp_ajax_save_critcss', array( $this, 'critcss_save_callback' ) ); add_action( 'wp_ajax_rm_critcss', array( $this, 'critcss_rm_callback' ) ); add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) ); add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) ); add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) ); add_action( 'wp_ajax_ao_ccss_queuerunner', array( $this, 'ao_ccss_queuerunner_callback' ) ); add_action( 'wp_ajax_ao_ccss_saverules', array( $this, 'ao_ccss_saverules_callback' ) ); } public function critcss_fetch_callback() { // Ajax handler to obtain a critical CSS file from the filesystem. // Check referer. check_ajax_referer( 'fetch_critcss_nonce', 'critcss_fetch_nonce' ); // Initialize error flag. $error = true; // Allow no content for MANUAL rules (as they may not exist just yet). if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) { $content = ''; $error = false; } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) { // Or check user permissios and filename. // Set file path and obtain its content. $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] ); if ( file_exists( $critcssfile ) ) { $content = file_get_contents( $critcssfile ); $error = false; } } // Prepare response. if ( $error ) { $response['code'] = '500'; $response['string'] = 'Error reading file ' . $critcssfile . '.'; } else { $response['code'] = '200'; $response['string'] = $content; } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function critcss_save_callback() { $error = false; $status = false; $response = array(); // Ajax handler to write a critical CSS to the filesystem // Check referer. check_ajax_referer( 'save_critcss_nonce', 'critcss_save_nonce' ); // Allow empty contents for MANUAL rules (as they are fetched later). if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) { $critcssfile = false; $status = true; } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) { // Or check user permissios and filename // Set critical CSS content. $critcsscontents = stripslashes( $_POST['critcsscontents'] ); // If there is content and it's valid, write the file. if ( $critcsscontents && $this->criticalcss->check_contents( $critcsscontents ) ) { // Set file path and status. $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] ); $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX ); // Or set as error. } else { $error = true; $critcssfile = 'CCSS content not acceptable.'; } // Or just set an error. } else { $error = true; $critcssfile = 'Not allowed or problem with CCSS filename.'; } // Prepare response. if ( ! $status || $error ) { $response['code'] = '500'; $response['string'] = 'Error saving file ' . $critcssfile . '.'; } else { $response['code'] = '200'; if ( $critcssfile ) { $response['string'] = 'File ' . $critcssfile . ' saved.'; if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) { $rule_identifiers = $this->fetch_rule_from_ccssfile( $critcssfile ); if ( ! empty( $rule_identifiers ) && is_array( $rule_identifiers ) ) { do_action( 'autoptimize_action_ccss_ajax_css_changed', $rule_identifiers[0], $critcssfile, $rule_identifiers[1] ); } } } else { $response['string'] = 'Empty content does not need to be saved.'; } } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function critcss_rm_callback() { // Ajax handler to delete a critical CSS from the filesystem // Check referer. check_ajax_referer( 'rm_critcss_nonce', 'critcss_rm_nonce' ); // Initialize error and status flags. $error = true; $status = false; // Allow no file for MANUAL rules (as they may not exist just yet). if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) { $error = false; } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) { // Or check user permissios and filename // Set file path and delete it. $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] ); if ( file_exists( $critcssfile ) ) { $status = unlink( $critcssfile ); $error = false; } } // Prepare response. if ( $error ) { $response['code'] = '500'; $response['string'] = 'Error removing file ' . $critcssfile . '.'; } else { $response['code'] = '200'; if ( $status ) { $response['string'] = 'File ' . $critcssfile . ' removed.'; if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) { $rule_identifiers = $this->fetch_rule_from_ccssfile( $critcssfile ); if ( ! empty( $rule_identifiers ) && is_array( $rule_identifiers ) ) { do_action( 'autoptimize_action_ccss_ajax_css_removed', $rule_identifiers[0], $critcssfile, $rule_identifiers[1] ); } } } else { $response['string'] = 'No file to be removed.'; } } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function critcss_rm_all_callback() { // Ajax handler to delete a critical CSS from the filesystem // Check referer. check_ajax_referer( 'rm_critcss_all_nonce', 'critcss_rm_all_nonce' ); // Initialize error and status flags. $error = true; $status = false; // Remove all ccss files on filesystem. if ( current_user_can( 'manage_options' ) ) { if ( file_exists( AO_CCSS_DIR ) && is_dir( AO_CCSS_DIR ) ) { array_map( 'unlink', glob( AO_CCSS_DIR . 'ccss_*.css', GLOB_BRACE ) ); $error = false; $status = true; if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) { do_action( 'autoptimize_action_ccss_ajax_all_css_removed' ); } } } // Prepare response. if ( $error ) { $response['code'] = '500'; $response['string'] = 'Error removing all critical CSS files.'; } else { $response['code'] = '200'; if ( $status ) { $response['string'] = 'Critical CSS Files removed.'; } else { $response['string'] = 'No file removed.'; } } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function ao_ccss_export_callback() { // Ajax handler export settings // Check referer. check_ajax_referer( 'ao_ccss_export_nonce', 'ao_ccss_export_nonce' ); if ( ! class_exists( 'ZipArchive' ) ) { $response['code'] = '500'; $response['msg'] = 'PHP ZipArchive not present, cannot create zipfile'; echo json_encode( $response ); wp_die(); } // Init array, get options and prepare the raw object. $settings = array(); // CCSS settings. $settings['ccss']['rules'] = get_option( 'autoptimize_ccss_rules' ); $settings['ccss']['additional'] = get_option( 'autoptimize_ccss_additional' ); $settings['ccss']['viewport'] = get_option( 'autoptimize_ccss_viewport' ); $settings['ccss']['finclude'] = get_option( 'autoptimize_ccss_finclude' ); $settings['ccss']['rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit' ); $settings['ccss']['noptimize'] = get_option( 'autoptimize_ccss_noptimize' ); $settings['ccss']['debug'] = get_option( 'autoptimize_ccss_debug' ); $settings['ccss']['key'] = get_option( 'autoptimize_ccss_key' ); $settings['ccss']['deferjquery'] = get_option( 'autoptimize_ccss_deferjquery' ); $settings['ccss']['domain'] = get_option( 'autoptimize_ccss_domain' ); $settings['ccss']['forcepath'] = get_option( 'autoptimize_ccss_forcepath' ); $settings['ccss']['loggedin'] = get_option( 'autoptimize_ccss_loggedin' ); $settings['ccss']['rlimit'] = get_option( 'autoptimize_ccss_rlimit' ); $settings['ccss']['unloadccss'] = get_option( 'autoptimize_ccss_unloadccss' ); // JS settings. $settings['js']['root'] = get_option( 'autoptimize_js' ); $settings['js']['aggregate'] = get_option( 'autoptimize_js_aggregate' ); $settings['js']['defer_not_aggregate'] = get_option( 'autoptimize_js_defer_not_aggregate' ); $settings['js']['defer_inline'] = get_option( 'autoptimize_js_defer_inline' ); $settings['js']['exclude'] = get_option( 'autoptimize_js_exclude' ); $settings['js']['forcehead'] = get_option( 'autoptimize_js_forcehead' ); $settings['js']['justhead'] = get_option( 'autoptimize_js_justhead' ); $settings['js']['trycatch'] = get_option( 'autoptimize_js_trycatch' ); $settings['js']['include_inline'] = get_option( 'autoptimize_js_include_inline' ); // CSS settings. $settings['css']['root'] = get_option( 'autoptimize_css' ); $settings['css']['aggregate'] = get_option( 'autoptimize_css_aggregate' ); $settings['css']['datauris'] = get_option( 'autoptimize_css_datauris' ); $settings['css']['justhead'] = get_option( 'autoptimize_css_justhead' ); $settings['css']['defer'] = get_option( 'autoptimize_css_defer' ); $settings['css']['defer_inline'] = get_option( 'autoptimize_css_defer_inline' ); $settings['css']['inline'] = get_option( 'autoptimize_css_inline' ); $settings['css']['exclude'] = get_option( 'autoptimize_css_exclude' ); $settings['css']['include_inline'] = get_option( 'autoptimize_css_include_inline' ); // Others. $settings['other']['autoptimize_imgopt_settings'] = get_option( 'autoptimize_imgopt_settings' ); $settings['other']['autoptimize_extra_settings'] = get_option( 'autoptimize_extra_settings' ); $settings['other']['autoptimize_cache_fallback'] = get_option( 'autoptimize_cache_fallback' ); $settings['other']['autoptimize_cache_nogzip'] = get_option( 'autoptimize_cache_nogzip' ); $settings['other']['autoptimize_cdn_url'] = get_option( 'autoptimize_cdn_url' ); $settings['other']['autoptimize_enable_meta_ao_settings'] = get_option( 'autoptimize_enable_meta_ao_settings' ); $settings['other']['autoptimize_enable_site_config'] = get_option( 'autoptimize_enable_site_config' ); $settings['other']['autoptimize_html'] = get_option( 'autoptimize_html' ); $settings['other']['autoptimize_html_keepcomments'] = get_option( 'autoptimize_html_keepcomments' ); $settings['other']['autoptimize_minify_excluded'] = get_option( 'autoptimize_minify_excluded' ); $settings['other']['autoptimize_optimize_checkout'] = get_option( 'autoptimize_optimize_checkout' ); $settings['other']['autoptimize_optimize_logged'] = get_option( 'autoptimize_optimize_logged' ); if ( defined( 'AO_PRO_VERSION' ) ) { $settings['pro']['boosters'] = get_option( 'autoptimize_pro_boosters' ); $settings['pro']['pagecache'] = get_option( 'autoptimize_pro_pagecache' ); } // Initialize error flag. $error = true; // Check user permissions. if ( current_user_can( 'manage_options' ) ) { // Prepare settings file path and content. $exportfile = AO_CCSS_DIR . 'settings.json'; $contents = json_encode( $settings ); $status = file_put_contents( $exportfile, $contents, LOCK_EX ); $error = false; } // Prepare archive. $zipfile = AO_CCSS_DIR . str_replace( array( '.', '/' ), '_', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ) . '_' . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip'; // @codingStandardsIgnoreLine $file = pathinfo( $zipfile, PATHINFO_BASENAME ); $zip = new ZipArchive(); $ret = $zip->open( $zipfile, ZipArchive::CREATE ); if ( true !== $ret ) { $error = true; } else { $zip->addFile( AO_CCSS_DIR . 'settings.json', 'settings.json' ); if ( file_exists( AO_CCSS_DIR . 'queue.json' ) ) { $zip->addFile( AO_CCSS_DIR . 'queue.json', 'queue.json' ); } $options = array( 'add_path' => './', 'remove_all_path' => true, ); $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options ); $zip->close(); } // settings.json has been added to zipfile, so can be removed now. if ( file_exists( $exportfile ) ) { unlink( $exportfile ); } // Prepare response. if ( ! $status || $error ) { $response['code'] = '500'; $response['msg'] = 'Error saving file ' . $file . ', code: ' . $ret; } else { $response['code'] = '200'; $response['msg'] = 'File ' . $file . ' saved.'; $response['file'] = $file; } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function ao_ccss_import_callback() { // Ajax handler import settings // Check referer. check_ajax_referer( 'ao_ccss_import_nonce', 'ao_ccss_import_nonce' ); // Initialize error flag. $error = false; // Process an uploaded file with no errors. if ( current_user_can( 'manage_options' ) && ! $_FILES['file']['error'] && $_FILES['file']['size'] < 500001 && strpos( $_FILES['file']['name'], '.zip' ) === strlen( $_FILES['file']['name'] ) - 4 ) { // create tmp dir with hard guess name in AO_CCSS_DIR. $_secret_dir = wp_hash( uniqid( md5( AUTOPTIMIZE_CACHE_URL ), true ) ); $_import_tmp_dir = trailingslashit( AO_CCSS_DIR . $_secret_dir ); mkdir( $_import_tmp_dir, 0774, true ); // Save file to that tmp directory but give it our own name to prevent directory traversal risks when using original name. $zipfile = $_import_tmp_dir . uniqid( 'import_settings-', true ) . '.zip'; move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile ); // Extract archive in the tmp directory. $zip = new ZipArchive; if ( $zip->open( $zipfile ) === true ) { // loop through all files in the zipfile. for ( $i = 0; $i < $zip->numFiles; $i++ ) { // @codingStandardsIgnoreLine // but only extract known good files. if ( preg_match( '/^settings\.json$|^\.\/ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) { $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) ); } } $zip->close(); } else { $error = 'could not extract'; } // and remove temp. dir with all contents (the import-zipfile). $this->rrmdir( $_import_tmp_dir ); if ( ! $error ) { // Archive extraction ok, continue importing settings from AO_CCSS_DIR. // Settings file. $importfile = AO_CCSS_DIR . 'settings.json'; if ( file_exists( $importfile ) ) { // Get settings and turn them into an object. $settings = json_decode( file_get_contents( $importfile ), true ); // Update options from settings, but only for known options. // CCSS. foreach ( array( 'rules', 'additional', 'viewport', 'finclude', 'rtimelimit', 'noptimize', 'debug', 'key', 'deferjquery', 'domain', 'forcepath', 'loggedin', 'rlimit', 'unloadccss' ) as $ccss_setting ) { if ( false === array_key_exists( 'ccss', $settings ) || false === array_key_exists( $ccss_setting, $settings['ccss'] ) ) { continue; } else { update_option( 'autoptimize_ccss_' . $ccss_setting, autoptimizeUtils::strip_tags_array( $settings['ccss'][ $ccss_setting ] ) ); } } // JS. foreach ( array( 'root', 'aggregate', 'defer_not_aggregate', 'defer_inline', 'exclude', 'forcehead', 'trycatch', 'include_inline' ) as $js_setting ) { if ( false === array_key_exists( 'js', $settings ) || false === array_key_exists( $js_setting, $settings['js'] ) ) { continue; } else if ( 'root' === $js_setting ) { update_option( 'autoptimize_js', $settings['js']['root'] ); } else { update_option( 'autoptimize_js_' . $js_setting, $settings['js'][ $js_setting ] ); } } // CSS. foreach ( array( 'root', 'aggregate', 'datauris', 'justhead', 'defer', 'defer_inline', 'inline', 'exclude', 'include_inline' ) as $css_setting ) { if ( false === array_key_exists( 'css', $settings ) || false === array_key_exists( $css_setting, $settings['css'] ) ) { continue; } else if ( 'root' === $css_setting ) { update_option( 'autoptimize_css', $settings['css']['root'] ); } else { update_option( 'autoptimize_css_' . $css_setting, $settings['css'][ $css_setting ] ); } } // Other. foreach ( array( 'autoptimize_imgopt_settings', 'autoptimize_extra_settings', 'autoptimize_cache_fallback', 'autoptimize_cache_nogzip', 'autoptimize_cdn_url', 'autoptimize_enable_meta_ao_settings', 'autoptimize_enable_site_config', 'autoptimize_html', 'autoptimize_html_keepcomments', 'autoptimize_minify_excluded', 'autoptimize_optimize_checkout', 'autoptimize_optimize_logged' ) as $other_setting ) { if ( false === array_key_exists( 'other', $settings ) || false === array_key_exists( $other_setting, $settings['other'] ) ) { continue; } else { update_option( $other_setting, $settings['other'][ $other_setting ] ); } } // AO Pro. if ( defined( 'AO_PRO_VERSION' ) && array_key_exists( 'pro', $settings ) ) { update_option( 'autoptimize_pro_boosters', $settings['pro']['boosters'] ); update_option( 'autoptimize_pro_pagecache', $settings['pro']['pagecache'] ); } // settings.json has been imported, so can be removed now. if ( file_exists( $importfile ) ) { unlink( $importfile ); } } else { // Settings file doesn't exist, update error flag. $error = 'settings file does not exist'; } } } else { $error = 'file could not be saved'; } // Prepare response. if ( $error ) { $response['code'] = '500'; $response['msg'] = 'Error importing settings: ' . $error; } else { $response['code'] = '200'; $response['msg'] = 'Settings imported successfully'; } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function ao_ccss_queuerunner_callback() { check_ajax_referer( 'ao_ccss_queuerunner_nonce', 'ao_ccss_queuerunner_nonce' ); // Process an uploaded file with no errors. if ( current_user_can( 'manage_options' ) ) { if ( ! file_exists( AO_CCSS_LOCK ) ) { $ccss_cron = new autoptimizeCriticalCSSCron(); $ccss_cron->ao_ccss_queue_control(); $response['code'] = '200'; $response['msg'] = 'Queue processing done'; } else { $response['code'] = '302'; $response['msg'] = 'Lock file found'; } } else { $response['code'] = '500'; $response['msg'] = 'Not allowed'; } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function ao_ccss_saverules_callback() { check_ajax_referer( 'ao_ccss_saverules_nonce', 'ao_ccss_saverules_nonce' ); // save rules over AJAX, too many users forget to press "save changes". if ( current_user_can( 'manage_options' ) ) { if ( array_key_exists( 'critcssrules', $_POST ) ) { $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045 . if ( ! empty( $rules ) ) { $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true ); if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) { $_safe_rules_array = array(); if ( array_key_exists( 'paths', $_unsafe_rules_array ) ) { $_safe_rules_array['paths'] = $_unsafe_rules_array['paths']; } if ( array_key_exists( 'types', $_unsafe_rules_array ) ) { $_safe_rules_array['types'] = $_unsafe_rules_array['types']; } $_safe_rules = json_encode( $_safe_rules_array, JSON_FORCE_OBJECT ); if ( ! empty( $_safe_rules ) ) { update_option( 'autoptimize_ccss_rules', $_safe_rules ); $response['code'] = '200'; $response['msg'] = 'Rules saved'; } else { $_error = 'Could not auto-save rules (safe rules empty)'; } } else { $_error = 'Could not auto-save rules (rules could not be json_decoded)'; } } else { $_error = 'Could not auto-save rules (rules empty)'; } } else { $_error = 'Could not auto-save rules (rules not in $_POST)'; } } else { $_error = 'Not allowed'; } if ( ! isset( $response ) && $_error ) { $response['code'] = '500'; $response['msg'] = $_error; } // Dispatch respose. echo json_encode( $response ); // Close ajax request. wp_die(); } public function critcss_check_filename( $filename ) { // Try to avoid directory traversal when reading/writing/deleting critical CSS files. if ( strpos( $filename, 'ccss_' ) !== 0 ) { return false; } elseif ( substr( $filename, -4, 4 ) !== '.css' ) { return false; } elseif ( sanitize_file_name( $filename ) !== $filename ) { // Use WordPress core's sanitize_file_name to see if anything fishy is going on. return false; } else { return true; } } public function rrmdir( $path ) { // recursively remove a directory as found on // https://andy-carter.com/blog/recursively-remove-a-directory-in-php. $files = glob( $path . '/*' ); foreach ( $files as $file ) { is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file ); } rmdir( $path ); return; } public function fetch_rule_from_ccssfile( $ccss_file = '' ) { if ( empty( $ccss_file ) ) { return false; } $ccss_file = str_replace( AO_CCSS_DIR, '', $ccss_file ); static $rules = null; if ( null === $rules ) { $rules = $this->criticalcss->get_option( 'rules' ); } foreach ( $rules as $ruletype => $rulechilds ) { foreach ( $rulechilds as $identifier => $properties ) { if ( $properties['file'] === $ccss_file ) { return array( $ruletype, $identifier ); } } } return false; } } PK ��3\���� � classes/autoptimizePartners.phpnu �[��� <?php /** * Handles adding "more tools" tab in AO admin settings page which promotes (future) AO * addons and/or affiliate services. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizePartners { public function __construct() { $this->run(); } public function run() { if ( $this->enabled() ) { add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_partner_tabs' ), 10, 1 ); } if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) { add_action( 'network_admin_menu', array( $this, 'add_admin_menu' ) ); } else { add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); } } protected function enabled() { return apply_filters( 'autoptimize_filter_show_partner_tabs', true ); } public function add_partner_tabs( $in ) { $in = array_merge( $in, array( 'ao_partners' => esc_html__( 'Optimize More!', 'autoptimize' ), ) ); return $in; } public function add_admin_menu() { if ( $this->enabled() ) { add_submenu_page( '', 'AO partner', 'AO partner', 'manage_options', 'ao_partners', array( $this, 'ao_partners_page' ) ); } } protected function get_ao_partner_feed_markup() { $no_feed_text = sprintf( esc_html__( 'Have a look at %1$sAutoptimize Pro%2$s to power-up your site!', 'autoptimize' ), '<a href="http://autoptimize.com/pro">', '</a>' ); $output = ''; if ( apply_filters( 'autoptimize_settingsscreen_remotehttp', true ) ) { $rss = fetch_feed( 'http://feeds.feedburner.com/OptimizingMattersDownloads' ); $maxitems = 0; if ( ! is_wp_error( $rss ) ) { $maxitems = $rss->get_item_quantity( 20 ); $rss_items = $rss->get_items( 0, $maxitems ); } if ( 0 == $maxitems ) { $output .= $no_feed_text; } else { $output .= '<ul>'; foreach ( $rss_items as $item ) { $item_url = esc_url( $item->get_permalink() ); $enclosure = $item->get_enclosure(); $output .= '<li class="itemDetail">'; $output .= '<h3 class="itemTitle"><a href="' . $item_url . '" target="_blank">' . esc_html( $item->get_title() ) . '</a></h3>'; if ( $enclosure && ( false !== strpos( $enclosure->get_type(), 'image' ) ) ) { $img_url = esc_url( $enclosure->get_link() ); $output .= '<div class="itemImage"><a href="' . $item_url . '" target="_blank"><img src="' . $img_url . '"></a></div>'; } $output .= '<div class="itemDescription">' . wp_kses_post( $item->get_description() ) . '</div>'; $output .= '<div class="itemButtonRow"><div class="itemButton button-secondary"><a href="' . $item_url . '" target="_blank">' . esc_html__( 'More info', 'autoptimize' ) . '</a></div></div>'; $output .= '</li>'; } $output .= '</ul>'; } } else { $output .= $no_feed_text; } return $output; } public function ao_partners_page() { ?> <style> .itemDetail { background: #fff; width: 250px; min-height: 290px; border: 1px solid #ccc; float: left; padding: 15px; position: relative; margin: 0 10px 10px 0; } .itemTitle { margin-top:0px; margin-bottom:10px; } .itemImage { text-align: center; } .itemImage img { max-width: 95%; max-height: 150px; } .itemDescription { margin-bottom:30px; } .itemButtonRow { position: absolute; bottom: 10px; right: 10px; width:100%; } .itemButton { float:right; } .itemButton a { text-decoration: none; color: #555; } .itemButton a:hover { text-decoration: none; color: #23282d; } </style> <script>document.title = "Autoptimize: <?php esc_html_e( 'Optimize More!', 'autoptimize' ); ?> " + document.title;</script> <div class="wrap"> <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html_e( 'Autoptimize Pro Settings', 'autoptimize' ) : esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1> <?php echo autoptimizeConfig::ao_admin_tabs(); ?> <?php echo '<h2>' . esc_html__( "These Autoptimize power-ups and related services will improve your site's performance even more!", 'autoptimize' ) . '</h2>'; ?> <div> <?php echo $this->get_ao_partner_feed_markup(); ?> </div> </div> <?php } } PK ��3\�y|B�1 �1 classes/autoptimizeImages.phpnu �[��� <?php /** * Handles optimizing images. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeImages { /** * Options. * * @var array */ protected $options = array(); /** * Singleton instance. * * @var self|null */ protected static $instance = null; /** * lazyload counter. * * @var int */ protected $lazyload_counter = 0; public function __construct( array $options = array() ) { // If options are not provided, fetch them. if ( empty( $options ) ) { $options = $this->fetch_options(); } $this->set_options( $options ); } public function set_options( array $options ) { $this->options = $options; return $this; } public static function fetch_options() { $value = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings' ); if ( empty( $value ) ) { // Fallback to returning defaults when no stored option exists yet. $value = autoptimizeConfig::get_ao_imgopt_default_options(); } // get service availability and add it to the options-array. $value['availabilities'] = autoptimizeOptionWrapper::get_option( 'autoptimize_service_availablity' ); if ( empty( $value['availabilities'] ) || ! is_array( $value['availabilities'] ) ) { $value['availabilities'] = null; if ( true === autoptimizeImages::imgopt_active() ) { $value['availabilities'] = autoptimizeUtils::check_service_availability( true ); } if ( null === $value['availabilities'] ) { // We can't seem to check service availability, use mock result with imgopt status UP. $_mock_settings = array( 'extra_imgopt' => array( 'status' => 'up', 'hosts' => array( '1' => 'https://sp-ao.shortpixel.ai/', ), ), 'critcss' => array( 'status' => 'up', ), ); $value['availabilities'] = $_mock_settings; } } return $value; } public static function imgopt_active() { // function to quickly check if imgopt is active, used below but also in // autoptimizeMain.php to start ob_ even if no HTML, JS or CSS optimizing is done // and does not use/ request the availablity data (which could slow things down). static $imgopt_active = null; if ( null === $imgopt_active ) { $opts = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings', '' ); if ( ! empty( $opts ) && is_array( $opts ) && array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $opts ) && ! empty( $opts['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $opts['autoptimize_imgopt_checkbox_field_1'] ) { $imgopt_active = true; } else { $imgopt_active = false; } } return $imgopt_active; } /** * Helper for getting a singleton instance. While being an * anti-pattern generally, it comes in handy for now from a * readability/maintainability perspective, until we get some * proper dependency injection going. * * @return self */ public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } public function run() { if ( is_admin() ) { if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) { add_action( 'network_admin_menu', array( $this, 'imgopt_admin_menu' ) ); } else { add_action( 'admin_menu', array( $this, 'imgopt_admin_menu' ) ); } add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_imgopt_tab' ), 9 ); } else { add_action( 'wp', array( $this, 'run_on_frontend' ) ); } } public function run_on_frontend() { if ( ! $this->should_run() ) { if ( $this->should_lazyload() ) { add_filter( 'wp_lazy_loading_enabled', array( $this, 'should_disable_core_lazyload' ), 10, 3 ); add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_lazyload_images' ), 10, 1 ); add_action( 'wp_footer', array( $this, 'add_lazyload_js_footer' ), 10, 0 ); } return; } $active = false; if ( apply_filters( 'autoptimize_filter_imgopt_do', true ) ) { add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_images' ), 10, 1 ); $active = true; } if ( apply_filters( 'autoptimize_filter_imgopt_do_css', true ) ) { // fixme: also act on already minified CSS! add_filter( 'autoptimize_filter_base_replace_cdn', array( $this, 'filter_optimize_css_images' ), 10, 1 ); add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_inline_css_images' ), 10, 1 ); $active = true; } if ( $active ) { add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_imgopt_url' ), 10, 1 ); } if ( $this->should_lazyload() ) { add_filter( 'wp_lazy_loading_enabled', array( $this, 'should_disable_core_lazyload' ), 10, 3 ); add_action( 'wp_footer', array( $this, 'add_lazyload_js_footer' ), 10, 0 ); } } /** * Disables core's native lazyload for images, not for iframes. * * @param bool $flag Incoming flag (mostly true). * @param string $tag Tag (img or iframe). * @param string $context Full context. * * @return bool */ public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) { if ( 'img' === $tag ) { return false; } return $flag; } /** * Basic checks before we can run. * * @return bool */ protected function should_run() { $opts = $this->options; $service_not_down = ( 'down' !== $opts['availabilities']['extra_imgopt']['status'] ); $not_launch_status = ( 'launch' !== $opts['availabilities']['extra_imgopt']['status'] ); $do_cdn = true; $_userstatus = $this->get_imgopt_provider_userstatus(); if ( isset( $_userstatus['Status'] ) && ( -2 == $_userstatus['Status'] || -3 == $_userstatus['Status'] ) ) { // don't even attempt to put images on CDN if heavily exceeded threshold or if site not reachable. $do_cdn = false; } if ( $this->imgopt_active() && $do_cdn && $service_not_down && ( $not_launch_status || $this->launch_ok() ) ) { return true; } return false; } public function get_imgopt_host() { static $imgopt_host = null; if ( null === $imgopt_host ) { $imgopt_host = 'https://sp-ao.shortpixel.ai/'; $avail_imgopt = $this->options['availabilities']['extra_imgopt']; if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) { $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) ); } $imgopt_host = apply_filters( 'autoptimize_filter_imgopt_host', $imgopt_host ); } return $imgopt_host; } public static function get_imgopt_host_wrapper() { // needed for CI tests. $self = new self(); return $self->get_imgopt_host(); } public static function get_service_url_suffix() { $suffix = '/af/ZQXTBY0109483/' . AUTOPTIMIZE_SITE_DOMAIN; return $suffix; } public function get_img_quality_string() { static $quality = null; if ( null === $quality ) { $q_array = $this->get_img_quality_array(); $setting = $this->get_img_quality_setting(); $quality = apply_filters( 'autoptimize_filter_imgopt_quality', 'q_' . $q_array[ $setting ] ); } return $quality; } public function get_img_quality_array() { static $map = null; if ( null === $map ) { $map = array( '1' => 'lossy', '2' => 'glossy', '3' => 'lossless', ); $map = apply_filters( 'autoptimize_filter_imgopt_quality_array', $map ); } return $map; } public function get_img_quality_setting() { static $q = null; if ( null === $q ) { if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_select_field_2', $this->options ) ) { $setting = $this->options['autoptimize_imgopt_select_field_2']; } if ( ! isset( $setting ) || empty( $setting ) || ( '1' !== $setting && '3' !== $setting ) ) { // default image opt. value is 2 ("glossy"). $q = '2'; } else { $q = $setting; } } return $q; } public function filter_preconnect_imgopt_url( array $in ) { $url_parts = parse_url( $this->get_imgopt_base_url() ); $in[] = $url_parts['scheme'] . '://' . $url_parts['host']; return $in; } /** * Makes sure given url contains the full scheme and hostname * in case they're not present already. * * @param string $in Image url to normalize. * * @return string */ private function normalize_img_url( $in ) { // Only parse the site url once. static $parsed_site_url = null; if ( null === $parsed_site_url ) { $parsed_site_url = parse_url( site_url() ); } // get CDN domain once. static $cdn_domain = null; if ( is_null( $cdn_domain ) ) { $cdn_url = $this->get_cdn_url(); if ( ! empty( $cdn_url ) ) { $cdn_domain = parse_url( $cdn_url, PHP_URL_HOST ); } else { $cdn_domain = ''; } } /** * This method gets called a lot, often for identical urls it seems. * `filter_optimize_css_images()` calls us, uses the resulting url and * gives it to `can_optimize_image()`, and if that returns trueish * then `build_imgopt_url()` is called (which, again, calls this method). * Until we dig deeper into whether this all must really happen that * way, having an internal cache here helps (to avoid doing repeated * identical string operations). */ static $cache = null; if ( null === $cache ) { $cache = array(); } // Do the work on cache miss only. if ( ! isset( $cache[ $in ] ) ) { // Default to (the trimmed version of) what was given to us. $result = trim( $in ); // Some silly plugins wrap background images in html-encoded quotes, so remove those from the img url. $result = $this->fix_silly_bgimg_quotes( $result ); if ( autoptimizeUtils::is_protocol_relative( $result ) ) { $result = $parsed_site_url['scheme'] . ':' . $result; } elseif ( 0 === strpos( $result, '/' ) ) { // Root-relative... $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result; } elseif ( ! empty( $cdn_domain ) && false === strpos( $this->get_imgopt_host(), $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) { // remove CDN except if it is the image optimization one. $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result ); } // filter (default off) to remove QS from image URL's to avoid eating away optimization credits. if ( apply_filters( 'autoptimize_filter_imgopt_no_querystring', false ) && strpos( $result, '?' ) !== false ) { $result = strtok( $result, '?' ); } $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result ); // Store in cache. $cache[ $in ] = $result; } return $cache[ $in ]; } public function filter_optimize_css_images( $in ) { $in = $this->normalize_img_url( $in ); if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) { return $this->build_imgopt_url( $in, '', '' ); } else { return $in; } } public function filter_optimize_inline_css_images( $html ) { preg_match_all( '#<style[^>]*>([^<]*)</style>#Um', $html, $inline_css_blocks, PREG_SET_ORDER ); foreach ( $inline_css_blocks as $inline_css_block ) { if ( false !== strpos( $inline_css_block[0], 'background' ) ) { $inline_css_block_new = $this->replace_background_img_css( $inline_css_block[0] ); if ( $inline_css_block_new !== $inline_css_block[0] ) { $html = str_replace( $inline_css_block[0], $inline_css_block_new, $html ); } } } return $html; } public static function replace_background_img_css( $css ) { // fixme; can/ should we cache these? preg_match_all( '#background[^;}]*url\((.*)\)#Ui', $css, $backgrounds, PREG_SET_ORDER ); if ( is_array( $backgrounds ) && ! empty( $backgrounds ) ) { foreach ( $backgrounds as $background ) { if ( autoptimizeImages::can_optimize_image_wrapper( $background[1] ) ) { $css = str_replace( $background[1], autoptimizeImages::build_imgopt_url_wrapper( $background[1] ), $css ); } } } return $css; } private function get_imgopt_base_url() { static $imgopt_base_url = null; if ( null === $imgopt_base_url ) { $imgopt_host = $this->get_imgopt_host(); $quality = $this->get_img_quality_string(); $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank. if ( $this->should_ngimg() ) { $sp_to_string = 'to_auto'; } else { $sp_to_string = 'to_webp'; } $sp_to_string = apply_filters( 'autoptimize_filter_imgopt_format', $sp_to_string ); // values: empty (= jpeg), to_webp (smart; webp or fallback), to_avif (avif or fallback) or to_auto (smart avif, webp or fallback). $imgopt_base_url = $imgopt_host . 'client/' . $sp_to_string . ',' . $quality . ',' . $ret_val; $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url ); } return $imgopt_base_url; } public static function can_optimize_image_wrapper( $url, $tag = '', $testing = false ) { $self = new self(); return $self->can_optimize_image( $url, $tag = '', $testing = false ); } private function can_optimize_image( $url, $tag = '', $testing = false ) { static $cdn_url = null; static $nopti_images = null; if ( null === $cdn_url ) { $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' ) ); } if ( null === $nopti_images || $testing ) { if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) { $nopti_images = $this->options['autoptimize_imgopt_text_field_6']; } $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images ); } $site_host = AUTOPTIMIZE_SITE_DOMAIN; $url = $this->normalize_img_url( $url ); $url_parsed = parse_url( $url ); if ( false === is_array( $url_parsed ) ) { return false; } elseif ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) { return false; } elseif ( autoptimizeUtils::is_local_server() ) { return false; } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) { return false; } elseif ( strpos( $url, '.php' ) !== false ) { return false; } elseif ( false === array_key_exists( 'path', $url_parsed ) || str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp', '.avif' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) { // fixme: better check against end of string. return false; } elseif ( ! empty( $nopti_images ) ) { $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) ); foreach ( $nopti_images_array as $nopti_image ) { if ( strpos( $url, $nopti_image ) !== false || ( ( '' !== $tag && strpos( $tag, $nopti_image ) !== false ) ) ) { return false; } } } return true; } // wrapper for reuse in AOPro. public static function build_imgopt_url_wrapper( $orig_url, $width = 0, $height = 0 ) { $self = new self(); return $self->build_imgopt_url( $orig_url, $width = 0, $height = 0 ); } private function build_imgopt_url( $orig_url, $width = 0, $height = 0 ) { // sanitize width and height. if ( strpos( $width, '%' ) !== false ) { $width = 0; } if ( strpos( $height, '%' ) !== false ) { $height = 0; } $width = (int) $width; $height = (int) $height; $filtered_url = apply_filters( 'autoptimize_filter_imgopt_build_url', $orig_url, $width, $height ); // If filter modified the url, return that. if ( $filtered_url !== $orig_url ) { return $filtered_url; } $normalized_url = $this->normalize_img_url( $orig_url ); // if the URL is ascii we check if we have a real URL with filter_var (which only works on ascii url's) and if not a real URL we return the original one. if ( apply_filters( 'autoptimize_filter_imgopt_check_normalized_url', true ) && ! preg_match( '/[^\x20-\x7e]/', $normalized_url ) && false === filter_var( $normalized_url, FILTER_VALIDATE_URL ) ) { return $orig_url; } $imgopt_base_url = $this->get_imgopt_base_url(); $imgopt_size = ''; if ( $width && 0 !== $width ) { $imgopt_size = ',w_' . $width; } if ( $height && 0 !== $height ) { $imgopt_size .= ',h_' . $height; } $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url; $url = apply_filters( 'autoptimize_filter_imgopt_after_build_imgopt_url', $url ); return $url; } public function replace_data_thumbs( $matches ) { return $this->replace_img_callback( $matches, 150, 150 ); } public function replace_img_callback( $matches, $width = 0, $height = 0 ) { $_normalized_img_url = $this->normalize_img_url( $matches[1] ); if ( $this->can_optimize_image( $matches[1], $matches[0] ) ) { return str_replace( $matches[1], $this->build_imgopt_url( $_normalized_img_url, $width, $height ), $matches[0] ); } else { return $matches[0]; } } public function replace_icon_callback( $matches ) { if ( array_key_exists( '2', $matches ) ) { $sizes = explode( 'x', $matches[2] ); $width = $sizes[0]; $height = $sizes[1]; } else { $width = 180; $height = 180; } // make sure we're not trying to optimize a *.ico file. if ( strpos( $matches[1], '.ico' ) === false ) { return $this->replace_img_callback( $matches, $width, $height ); } else { return $matches[0]; } } public function filter_optimize_images( $in, $testing = false ) { /* * potential future functional improvements: * * filter for critical CSS. */ $to_replace = array(); $to_preload = ''; // hide (no)script tags to avoid replacing (and potentially breaking) images in script tags. if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) { $in = autoptimizeBase::replace_contents_with_marker_if_exists( 'SCRIPT', '<script', '#<(?:no)?script.*?<\/(?:no)?script>#is', $in ); } // get img preloads as set in post metabox, exploding ", " instead of "," because LCP preload // could be a shortpixel URL, which has comma's and results in way too many preloads. $metabox_preloads = array_filter( array_map( 'trim', explode( ', ', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) ); $metabox_preloads = apply_filters( 'autoptimize_filter_images_metabox_preloads', $metabox_preloads ); // extract img tags. if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) { foreach ( $matches[0] as $tag ) { $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt', $tag ); $orig_tag = $tag; $imgopt_w = ''; $imgopt_h = ''; // first do (data-)srcsets. if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) { foreach ( $allsrcsets as $srcset ) { $srcset = $srcset[2]; $orig_srcset = $srcset; $srcsets = explode( ',', $srcset ); foreach ( $srcsets as $indiv_srcset ) { $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) ); if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) { $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' ); } if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) { $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' ); $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset ); } } $tag = str_replace( $orig_srcset, $srcset, $tag ); } } // proceed with img src. // get width and height and add to $imgopt_size. $_get_size = $this->get_size_from_tag( $tag ); $imgopt_w = $_get_size['width']; $imgopt_h = $_get_size['height']; // then start replacing images src. if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) { foreach ( $urls as $url ) { $full_src_orig = $url[0]; $url = $url[1]; if ( $this->can_optimize_image( $url, $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) { $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h ); $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig ); $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag ); } } } // check if the image needs to be prelaoded. if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) { $to_preload .= $this->create_img_preload_tag( $tag ); } // do lazyload stuff. if ( $this->should_lazyload( $in ) && ! empty( $url ) ) { // first do lpiq placeholder logic. if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) { // if all img src have been replaced during srcset, we have to extract the // origin url from the imgopt one to be able to set a lqip placeholder. $_url = substr( $url, strpos( $url, '/http' ) + 1 ); } else { $_url = $url; } $_url = $this->normalize_img_url( $_url ); $placeholder = ''; if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', false, $_url ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) { $lqip_w = ''; $lqip_h = ''; if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) { $lqip_w = ',w_' . $imgopt_w; } if ( isset( $imgopt_h ) && ! empty( $imgopt_h ) ) { $lqip_h = ',h_' . $imgopt_h; } $placeholder = $this->get_imgopt_host() . 'client/q_lqip,ret_wait' . $lqip_w . $lqip_h . '/' . $_url; } // then call add_lazyload-function with lpiq placeholder if set. $tag = $this->add_lazyload( $tag, $placeholder ); } // add decoding="async" behind filter, not sure if I'll make it default true yet. if ( true === apply_filters( 'autoptimize_filter_imgopt_add_decoding', true ) && false === strpos( $tag, ' decoding=' ) ) { $tag = str_replace( '<img ', '<img decoding="async" ', $tag ); } $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt', $tag ); // and add tag to array for later replacement. if ( $tag !== $orig_tag ) { $to_replace[ $orig_tag ] = $tag; } } } // and replace all. $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in ); // misc. node attributes that might hold image url's (incl. the previously separate data-thumb). $extra_attr_with_img = apply_filters( 'autoptimize_filter_imgopt_attr_with_img', array( array( 'div', 'data-thumb'), array( 'div', 'data-background' ), array( 'img', 'data-retina' ) ) ); if ( ! empty( $extra_attr_with_img ) && is_array( $extra_attr_with_img ) ) { foreach ( $extra_attr_with_img as $candidate ) { if ( is_array( $candidate ) && strpos( $out, $candidate[1] ) !== false ) { $_regex = '/\<' . $candidate[0] . '(?:[^>]*)?\s' . $candidate[1] . '=(?:"|\')(.+?)(?:"|\')(?:[^>]*)?>/s'; $out = preg_replace_callback( $_regex, array( $this, 'replace_img_callback' ), $out ); } } } // background-image in inline style. if ( ( strpos( $out, 'background-image:' ) !== false || strpos( $out, 'background:' ) !== false ) && strpos( $out, 'url(' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) { $out = preg_replace_callback( '/style=(?:"|\')[^<>]*?background(?:-image)?:[^;"\'()>]*url\((?:"|\')?([^"\')]*)(?:"|\')?\)/', array( $this, 'replace_img_callback' ), $out ); } // act on icon links. if ( ( strpos( $out, '<link rel="icon"' ) !== false || ( strpos( $out, "<link rel='icon'" ) !== false ) ) && apply_filters( 'autoptimize_filter_imgopt_linkicon', true ) ) { $out = preg_replace_callback( '/<link\srel=(?:"|\')(?:apple-touch-)?icon(?:-precomposed)?(?:"|\').*\shref=(?:"|\')(.*)(?:"|\')(?:\ssizes=(?:"|\')(\d*x\d*)(?:"|\'))?\s?\/?>/Um', array( $this, 'replace_icon_callback' ), $out ); } // lazyload picture source tags and bgimage. if ( $this->should_lazyload() ) { $out = $this->process_picture_tag( $out, true, true ); $out = $this->process_bgimage( $out ); } else { $out = $this->process_picture_tag( $out, true, false ); } // restore (no)script tags. if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) { $out = autoptimizeBase::restore_marked_content( 'SCRIPT', $out ); } if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) { // the preload was not in an img tag, so adding a non-responsive preload instead. foreach ( $metabox_preloads as $img_preload ) { $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">'; } } if ( ! empty( $to_preload ) ) { $out = autoptimizeExtra::inject_preloads( $to_preload, $out ); } return $out; } public static function get_size_from_tag( $tag ) { // reusable function to extract widht and height from an image tag // enforcing a filterable maximum width and height (default 4999X4999). $width = ''; $height = ''; if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $_width ) ) { if ( strpos( $_width[2], '%' ) === false ) { $width = (int) $_width[2]; } } if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $_height ) ) { if ( strpos( $_height[2], '%' ) === false ) { $height = (int) $_height[2]; } } // check for and enforce (filterable) max sizes. $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 ); if ( $width > $_max_width ) { $_width = $_max_width; if ( ! empty( $height ) && is_int( $height ) ) { $height = $_width / $width * $height; } $width = $_width; } $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 ); if ( $height > $_max_height ) { $_height = $_max_height; if ( ! empty( $width ) && is_int( $width ) ) { $width = $_height / $height * $width; } $height = $_height; } return array( 'width' => $width, 'height' => $height, ); } /** * Lazyload functions */ public static function should_lazyload_wrapper( $no_meta = false ) { // needed in autoptimizeMain.php. $self = new self(); return $self->should_lazyload( '', $no_meta ); } public function should_lazyload( $context = '', $no_meta = false ) { if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && false === $this->check_nolazy() ) { $lazyload_return = true; } else { $lazyload_return = false; } // If page/ post check post_meta to see if lazyload is off for page. if ( false === $no_meta && false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_lazyload' ) ) { $lazyload_return = false; } $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context ); return $lazyload_return; } public static function check_nolazy() { if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) { return true; } else { return false; } } public function filter_lazyload_images( $in ) { // only used is image optimization is NOT active but lazyload is. $to_replace = array(); $to_preload = ''; // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript). $out = autoptimizeBase::replace_contents_with_marker_if_exists( 'SCRIPT', '<script', '#<(?:no)?script.*?<\/(?:no)?script>#is', $in ); // get img preloads as set in post metabox. $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) ); // extract img tags and add lazyload attribs/ add preloads. if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) { foreach ( $matches[0] as $tag ) { // check if image needs to be preloaded. if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) { $to_preload .= $this->create_img_preload_tag( $tag ); } // and lazyloaded. if ( $this->should_lazyload( $out ) ) { $to_replace[ $tag ] = $this->add_lazyload( $tag ); } } $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out ); } // and also lazyload picture tag. $out = $this->process_picture_tag( $out, false, true ); // and inline style blocks with background-image. $out = $this->process_bgimage( $out ); // restore noscript tags. $out = autoptimizeBase::restore_marked_content( 'SCRIPT', $out ); if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) { // the preload was not in an img tag, so adding a non-responsive preload instead. foreach ( $metabox_preloads as $img_preload ) { $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">'; } } if ( ! empty( $to_preload ) ) { $out = autoptimizeExtra::inject_preloads( $to_preload, $out ); } return $out; } public function add_lazyload( $tag, $placeholder = '' ) { // adds actual lazyload-attributes to an image node. $this->lazyload_counter++; $_lazyload_from_nth = ''; if ( array_key_exists( 'autoptimize_imgopt_number_field_7', $this->options ) ) { $_lazyload_from_nth = $this->options['autoptimize_imgopt_number_field_7']; } $_lazyload_from_nth = apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', $_lazyload_from_nth ); if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= $_lazyload_from_nth ) { $tag = $this->maybe_fix_missing_quotes( $tag ); // store original tag for use in noscript version. $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>'; $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' ); // insert lazyload class. $tag = $this->inject_classes_in_tag( $tag, "$lazyload_class " ); if ( ! $placeholder || empty( $placeholder ) ) { // get image width & heigth for placeholder fun (and to prevent content reflow). $_get_size = $this->get_size_from_tag( $tag ); $width = $_get_size['width']; $height = $_get_size['height']; if ( false === $width || empty( $width ) ) { $width = 210; // default width for SVG placeholder. } if ( false === $height || empty( $height ) ) { $height = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio. } // insert the actual lazyload stuff. // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's. $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( $width, $height ) ); } $tag = preg_replace( '/(\s)src=/', ' src=\'' . $placeholder . '\' data-src=', $tag ); $tag = preg_replace( '/(\s)srcset=/', ' data-srcset=', $tag ); // move sizes to data-sizes unless filter says no. if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_move_sizes', true ) ) { $tag = str_replace( ' sizes=', ' data-sizes=', $tag ); } // add the noscript-tag from earlier. $tag = $noscript_tag . $tag; $tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag ); } else { $tag = apply_filters( 'autoptimize_filter_imgopt_not_lazyloaded_img', $tag ); } return $tag; } public function add_lazyload_js_footer() { if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup( '' ) ) { return; } // The JS will by default be excluded form autoptimization but this can be changed with a filter. $noptimize_flag = ''; if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) { $noptimize_flag = ' data-noptimize="1"'; } $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' ); if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) { // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves :-) ? $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ ); } else { $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ ); } $cdn_url = $this->get_cdn_url(); if ( ! empty( $cdn_url ) ) { $cdn_url = rtrim( $cdn_url, '/' ); $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js ); } $type_js = ''; if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) { $type_js = ' type="text/javascript"'; } // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async). echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' ); echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' ); echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' ); } public static function create_img_preload_tag( $tag ) { if ( false === apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) { return ''; } // clean up; remove tabs/ linebreaks/ spaces. $tag = preg_replace( '/\s+/', ' ', $tag ); // remove noscript. if ( false !== strpos( $tag, '<noscript' ) ) { $tag = preg_replace( '/<noscript.*<\/noscript>/mU', '', $tag ); } // rewrite img tag to link preload img. $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' ); $_to = array( '<link rel="preload" as="image" ', ' href=', ' imagesizes=', ' imagesrcset=' ); $tag = str_replace( $_from, $_to, $tag ); // and remove title, alt, class and id. $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy|width|height)=".*")/Um', '', $tag ); if ( str_replace( array( ' title=', ' class=', ' alt=', ' id=', ' fetchpriority=', ' decoding=', ' data-no-lazy=' ), '', $tag ) !== $tag ) { // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles. $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy)=\'.*\')/Um', '', $tag ); } return $tag; } public static function get_cdn_url() { // getting CDN url here to avoid having to make bigger changes to autoptimizeBase. static $cdn_url = null; if ( null === $cdn_url ) { $cdn_url = autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' ); $cdn_url = autoptimizeUtils::tweak_cdn_url_if_needed( $cdn_url ); $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url ); } return $cdn_url; } public function get_lazyload_exclusions() { // returns array of strings that if found in an <img tag will stop the img from being lazy-loaded. static $exclude_lazyload_array = null; if ( null === $exclude_lazyload_array ) { $options = $this->options; // set default exclusions. $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg', 'loading="eager"', 'fetchpriority="high"' ); // add from setting. if ( array_key_exists( 'autoptimize_imgopt_text_field_5', $options ) ) { $exclude_lazyload_option = $options['autoptimize_imgopt_text_field_5']; if ( ! empty( $exclude_lazyload_option ) ) { $exclude_lazyload_array = array_merge( $exclude_lazyload_array, array_filter( array_map( 'trim', explode( ',', $options['autoptimize_imgopt_text_field_5'] ) ) ) ); } } // and filter for developer-initiated changes. $exclude_lazyload_array = apply_filters( 'autoptimize_filter_imgopt_lazyload_exclude_array', $exclude_lazyload_array ); } return $exclude_lazyload_array; } public function inject_classes_in_tag( $tag, $target_class ) { if ( strpos( $tag, 'class=' ) !== false ) { $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag ); } else { $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag ); } return $tag; } public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) { return 'data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20' . $imgopt_w . '%20' . $imgopt_h . '%22%3E%3C/svg%3E'; } public function should_ngimg() { static $ngimg_return = null; if ( is_null( $ngimg_return ) ) { // nextgen img only works if imgopt is active. if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && $this->imgopt_active() ) { $ngimg_return = true; } else { $ngimg_return = false; } } return $ngimg_return; } public function process_picture_tag( $in, $imgopt = false, $lazy = false ) { // check if "<picture" is present and if filter allows us to process <picture>. if ( strpos( $in, '<picture' ) === false || apply_filters( 'autoptimize_filter_imgopt_dopicture', true ) === false ) { return $in; } $_exclusions = $this->get_lazyload_exclusions(); $to_replace_pict = array(); // extract and process each picture-node. preg_match_all( '#<picture.*</picture>#Usmi', $in, $_pictures, PREG_SET_ORDER ); foreach ( $_pictures as $_picture ) { $_picture = $this->maybe_fix_missing_quotes( $_picture ); if ( strpos( $_picture[0], '<source ' ) !== false && preg_match_all( '#<source .*srcset=(?:"|\')(?!data)(.*)(?:"|\').*>#Usmi', $_picture[0], $_sources, PREG_SET_ORDER ) !== false ) { foreach ( $_sources as $_source ) { $_picture_replacement = $_source[0]; // should we optimize the image? if ( $imgopt && $this->can_optimize_image( $_source[1], $_picture[0] ) ) { $_picture_replacement = str_replace( $_source[1], $this->build_imgopt_url( $_source[1] ), $_picture_replacement ); } // should we lazy-load? if ( $lazy && $this->should_lazyload() && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) { $_picture_replacement = str_replace( ' srcset=', ' data-srcset=', $_picture_replacement ); } $to_replace_pict[ $_source[0] ] = $_picture_replacement; } } } // and return the fully procesed $in. $out = str_replace( array_keys( $to_replace_pict ), array_values( $to_replace_pict ), $in ); return $out; } public function process_bgimage( $in ) { if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) { $out = preg_replace_callback( '/(<(?:article|aside|body|div|footer|header|p|section|span|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/', array( $this, 'lazyload_bgimg_callback' ), $in ); return $out; } return $in; } public function lazyload_bgimg_callback( $matches ) { if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) { // get placeholder & lazyload class strings. $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) ); $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' ); // remove quotes from url() to be able to replace in next step. $out = str_replace( array( "url('" . $matches[2] . "')", 'url("' . $matches[2] . '")' ), 'url(' . $matches[2] . ')', $matches[0] ); // replace background-image URL with SVG placeholder. $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $out ); // sanitize bgimg src for quote sillyness. $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] ); // add data-bg attribute with real background-image URL for lazyload to pick up. $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $bgimg_src . '"', $out ); // and finally add lazyload class to tag. $out = $this->inject_classes_in_tag( $out, "$lazyload_class " ); return $out; } return $matches[0]; } public function fix_silly_bgimg_quotes( $tag_in ) { // some themes/ pagebuilders wrap backgroundimages in HTML-encoded quotes (or linebreaks) which breaks imgopt/ lazyloading, this removes them. return trim( str_replace( array( "\r\n", '"', '"', '"', ''', ''' ), '', $tag_in ) ); } public function maybe_fix_missing_quotes( $tag_in ) { // W3TC's Minify_HTML class removes quotes around attribute value, this re-adds them for the class and width/height attributes so we can lazyload properly. if ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) { $tag_out = preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in ); $tag_out = preg_replace( '/\s(width|height)=(?:"|\')?([^\s"\'>]*)(?:"|\')?/', ' $1=\'$2\'', $tag_out ); return $tag_out; } else { return $tag_in; } } /** * Admin page logic and related functions below. */ public function imgopt_admin_menu() { // no acces if multisite and not network admin and no site config allowed. if ( autoptimizeConfig::should_show_menu_tabs() ) { add_submenu_page( '', 'autoptimize_imgopt', 'autoptimize_imgopt', 'manage_options', 'autoptimize_imgopt', array( $this, 'imgopt_options_page' ) ); } register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' ); } public function add_imgopt_tab( $in ) { if ( autoptimizeConfig::should_show_menu_tabs() ) { $in = array_merge( $in, array( 'autoptimize_imgopt' => apply_filters( 'autoptimize_filter_imgopt_tab_text', esc_html__( 'Images', 'autoptimize' ) ) ) ); } return $in; } public function imgopt_options_page() { // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace // phpcs:disable Generic.Formatting.DisallowMultipleStatements.SameLine // Check querystring for "refreshCacheChecker" and call cachechecker if so. if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) { $this->query_img_provider_stats( true ); } $options = $this->fetch_options(); $sp_url_suffix = $this->get_service_url_suffix(); ?> <style> #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;} #ao_settings_form .form-table th {font-weight: normal;} #autoptimize_imgopt_descr{font-size: 120%;} </style> <script>document.title = "Autoptimize: <?php esc_html_e( 'Images', 'autoptimize' ); ?> " + document.title;</script> <div class="wrap"> <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html_e( 'Autoptimize Pro Settings', 'autoptimize' ) : esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1> <?php echo autoptimizeConfig::ao_admin_tabs(); ?> <?php if ( autoptimizeUtils::is_local_server() ) { ?> <div class="notice-warning notice"><p> <?php echo esc_html__( 'The image optimization service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' ); ?> </p></div> <?php } ?> <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?> <div class="notice-warning notice"><p> <?php // translators: "Autoptimize support forum" will appear in a "a href". echo sprintf( esc_html__( 'The image optimization service is currently down, image optimization will be skipped until further notice. Check the %1$sAutoptimize support forum%2$s for more info.', 'autoptimize' ), '<a href="https://wordpress.org/support/plugin/autoptimize/" target="_blank">', '</a>' ); ?> </p></div> <?php } ?> <?php if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! autoptimizeImages::instance()->launch_ok() ) { ?> <div class="notice-warning notice"><p> <?php esc_html_e( 'The image optimization service is launching, but not yet available for this domain, it should become available in the next couple of days.', 'autoptimize' ); ?> </p></div> <?php } ?> <?php if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) { ?> <div class="notice-warning notice"><p> <?php // translators: "disable Jetpack's site accelerator for images" will appear in a "a href" linking to the jetpack settings page. echo sprintf( esc_html__( 'Please %1$sdisable Jetpack\'s site accelerator for images%2$s to be able to use Autoptomize\'s advanced image optimization features below.', 'autoptimize' ), '<a href="admin.php?page=jetpack#/settings">', '</a>' ); ?> </p></div> <?php } ?> <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'> <?php settings_fields( 'autoptimize_imgopt_settings' ); ?> <h2><?php esc_html_e( 'Image optimization', 'autoptimize' ); ?></h2> <span id='autoptimize_imgopt_descr'><?php echo apply_filters( 'autoptimize_filter_imgopt_intro_copy', esc_html__( 'Make your site significantly faster by simply ticking a few boxes and start serving CDN powered, optimized images in next-get formats like WebP and AVIF! No additional plugins or services needed.', 'autoptimize' ) ); ?></span> <table class="form-table"> <tr> <th scope="row"><?php esc_html_e( 'Image optimization & CDN', 'autoptimize' ); ?></th> <td> <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php echo apply_filters( 'autoptimize_filter_imgopt_main_setting_copy', esc_html__( 'On-the-fly image optimization and fast delivery via the Shortpixel global CDN.', 'autoptimize' ) ); ?></label> <?php // show shortpixel status. $_notice = autoptimizeImages::instance()->get_imgopt_status_notice(); if ( $_notice ) { switch ( $_notice['status'] ) { case 2: $_notice_color = 'green'; break; case 1: $_notice_color = 'orange'; break; case -1: case -2: case -3: $_notice_color = 'red'; break; default: $_notice_color = 'green'; } echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . esc_html__( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' ); } else { // translators: link points to shortpixel. $upsell_msg_1 = '<p>' . sprintf( esc_html__( 'Get more Google love by speeding up your website. Start serving on-the-fly optimized images (also in the "next-gen" %4$sWebP%5$s and %4$sAVIF%5$s image formats) by %1$sShortPixel%2$s. No additional image optimization plugins are needed: your images are optimized, cached and served from %3$sShortPixel\'s global CDN%2$s.', 'autoptimize' ), '<a href="https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell" target="_blank">', '</a>', '<a href="https://help.shortpixel.com/article/62-where-does-the-cdn-has-pops" target="_blank">', '<strong>', '</strong>' ); if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) { $upsell_msg_2 = sprintf( esc_html__( 'For a limited time only, this service is offered free for all Autoptimize users, %1$sdon\'t miss the chance to test it%2$s and see how much it could improve your site\'s speed.', 'autoptimize' ), '<strong>', '</strong>' ); } else { // translators: 1st link points to autoptimize.com.pro, 2nd to shortpixel. $upsell_msg_2 = sprintf( esc_html__( 'For (nearly) %5$sunlimited image optimizations %1$sbuy Autoptimize Pro%2$s%6$s which also includes Critical CSS and extra "booster" options or %3$ssign up at Shortpixel%4$s.', 'autoptimize' ), '<a href="https://autoptimize.com/pro/" target="_blank">', '</a>', '<a href="https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell" target="_blank">', '</a>', '<strong>', '</strong>' ); } echo apply_filters( 'autoptimize_filter_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' ); } // translators: link points to shortpixel FAQ. $faqcopy = sprintf( esc_html__( '%3$sQuestions%4$s? Take a look at the %1$sAutoptimize + ShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://help.shortpixel.com/category/405-autoptimize" target="_blank">', '</strong></a>', '<strong>', '</strong>' ); $faqcopy = $faqcopy . ' ' . esc_html__( 'Only works for websites and images that are publicly available.', 'autoptimize' ); // translators: links points to shortpixel TOS & Privacy Policy. $toscopy = sprintf( esc_html__( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/privacy' . $sp_url_suffix . '" target="_blank">', '</a>' ); echo apply_filters( 'autoptimize_filter_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' ); ?> </td> </tr> <tr id='autoptimize_imgopt_optimization_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>> <th scope="row"><?php esc_html_e( 'Optimization exclusions', 'autoptimize' ); ?></th> <td> <label><input type='text' style='width:80%' id='autoptimize_imgopt_optimization_exclusions' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_6]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_6'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_6'] ); } ?>'><br /><?php esc_html_e( 'Comma-separated list of image classes or filenames that should not be optimized.', 'autoptimize' ); ?></label> </td> </tr> <tr id='autoptimize_imgopt_quality' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>> <th scope="row"><?php esc_html_e( 'Image Optimization quality', 'autoptimize' ); ?></th> <td> <label> <select name='autoptimize_imgopt_settings[autoptimize_imgopt_select_field_2]'> <?php $_imgopt_array = autoptimizeImages::instance()->get_img_quality_array(); $_imgopt_val = autoptimizeImages::instance()->get_img_quality_setting(); foreach ( $_imgopt_array as $key => $value ) { echo '<option value="' . $key . '"'; if ( $_imgopt_val == $key ) { echo ' selected'; } echo '>' . ucfirst( $value ) . '</option>'; } echo "\n"; ?> </select> </label> <p> <?php // translators: link points to shortpixel image test page. echo apply_filters( 'autoptimize_filter_imgopt_quality_copy', sprintf( esc_html__( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/online-image-compression' . $sp_url_suffix . '" target="_blank">', '</a>' ) ); ?> </p> </td> </tr> <?php if ( apply_filters( 'autoptimize_filter_imgopt_settings_show_avif', true ) ) { ?> <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>> <th scope="row"><?php esc_html_e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th> <td> <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_4'] ) { echo 'checked="checked"'; } ?> value='1'><?php esc_html_e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?></label> </td> </tr> <?php } else { ?> <input type='hidden' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' value='0'> <?php } ?> <tr> <th scope="row"><?php esc_html_e( 'Lazy-load images?', 'autoptimize' ); ?></th> <td> <label><input type='checkbox' id='autoptimize_imgopt_lazyload_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_3]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php esc_html_e( 'Image lazy-loading will delay the loading of non-visible images to allow the browser to optimally load all resources for the "above the fold"-page first.', 'autoptimize' ); ?></label> </td> </tr> <tr id='autoptimize_imgopt_lazyload_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="autoptimize_lazyload_child hidden"'; } else { echo 'class="autoptimize_lazyload_child"'; } ?>> <th scope="row"><?php esc_html_e( 'Lazy-load exclusions', 'autoptimize' ); ?></th> <td> <label><input type='text' style='width:80%' id='autoptimize_imgopt_lazyload_exclusions_text' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_5]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_5'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_5'] ); } ?>'><br /><?php esc_html_e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label> </td> </tr> <tr id='autoptimize_imgopt_lazyload_from_nth_image' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="autoptimize_lazyload_child hidden"'; } else { echo 'class="autoptimize_lazyload_child"'; } ?>> <th scope="row"><?php esc_html_e( 'Lazy-load from nth image', 'autoptimize' ); ?></th> <td> <label><input type='number' min='0' max='50' style='width:80%' id='autoptimize_imgopt_lazyload_from_nth_image_number' name='autoptimize_imgopt_settings[autoptimize_imgopt_number_field_7]' value='<?php if ( ! empty( $options['autoptimize_imgopt_number_field_7'] ) ) { echo esc_attr( $options['autoptimize_imgopt_number_field_7'] ); } else { echo '1'; } ?>'><br /><?php esc_html_e( 'Don\'t lazyload the first X images, \'1\' lazyloads all.', 'autoptimize' ); ?></label> </td> </tr> </table> <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_html_e( 'Save Changes', 'autoptimize' ); ?>" /></p> </form> <script> jQuery(document).ready(function() { jQuery("#autoptimize_imgopt_checkbox").change(function() { if (this.checked) { jQuery("#autoptimize_imgopt_quality").show("slow"); jQuery("#autoptimize_imgopt_ngimg").show("slow"); jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow"); } else { jQuery("#autoptimize_imgopt_quality").hide("slow"); jQuery("#autoptimize_imgopt_ngimg").hide("slow"); jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow"); } }); jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() { if (this.checked) { jQuery(".autoptimize_lazyload_child").show("slow"); } else { jQuery(".autoptimize_lazyload_child").hide("slow"); } }); }); </script> <?php } /** * Ïmg opt status as used on dashboard. */ public function get_imgopt_status_notice() { if ( $this->imgopt_active() && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) { $_imgopt_notice = ''; $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' ); $_site_host = AUTOPTIMIZE_SITE_DOMAIN; $_imgopt_upsell = 'https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell'; $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account'; $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai'; if ( is_array( $_stat ) ) { if ( 1 == $_stat['Status'] ) { // translators: "add more credits" will appear in a "a href". $_imgopt_notice = sprintf( esc_html__( 'Your ShortPixel image optimization and CDN quota is almost used, make sure you %1$sadd more credits%2$s to avoid slowing down your website %4$sor consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization%5$s but also automated critical CSS and extra booster options.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>', '<a href="https://autoptimize.com/pro/" target="_blank">', '<strong>', '</strong>' ); } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) { // translators: "add more credits" will appear in a "a href". $_imgopt_notice = sprintf( esc_html__( 'Your ShortPixel image optimization and CDN quota has been exhausted, %1$sadd more credits%2$s to continue to quickly deliver optimized images on your website %4$sor consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization%5$s but also automated critical CSS and extra booster options.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>', '<a href="https://autoptimize.com/pro/" target="_blank">', '<strong>', '</strong>' ); // translators: "associate your domain" will appear in a "a href". $_imgopt_notice = $_imgopt_notice . ' ' . sprintf( esc_html__( 'If you have enough CDN quota remaining, then you may need to %1$sassociate your domain%2$s to your Shortpixel account.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $_imgopt_assoc . '" target="_blank">', '</a>' ); } elseif ( -3 == $_stat['Status'] ) { // translators: "check the documentation here" will appear in a "a href". $_imgopt_notice = sprintf( esc_html__( 'It seems ShortPixel image optimization is not able to fetch images from your site, %1$scheck the documentation here%2$s for more information', 'autoptimize' ), '<a href="' . $_imgopt_unreach . '" target="_blank">', '</a>' ); } else { $_imgopt_upsell = 'https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell'; // translators: "log in to check your account" will appear in a "a href". $_imgopt_notice = sprintf( esc_html__( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' ); } // add info on freshness + refresh link if status is not 2 (good shape). if ( 2 != $_stat['Status'] ) { $_imgopt_stats_refresh_url = add_query_arg( array( 'page' => 'autoptimize_imgopt', 'refreshImgProvStats' => '1', ), admin_url( 'options-general.php' ) ); if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) { $_imgopt_stats_last_run = esc_html__( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] ); } else { $_imgopt_stats_last_run = esc_html__( 'based on previously fetched data', 'autoptimize' ); } $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', '; // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats. $_imgopt_notice .= sprintf( esc_html__( 'you can click %1$shere to refresh your quota status%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' ); } // and make the full notice filterable. $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice ); return array( 'status' => $_stat['Status'], 'notice' => $_imgopt_notice, ); } } return false; } public static function get_imgopt_status_notice_wrapper() { // needed for notice being shown in autoptimizeCacheChecker.php. $self = new self(); return $self->get_imgopt_status_notice(); } /** * Get img provider stats (used to display notice). * * @param bool $_refresh Should the stats be forcefully refreshed or not. */ public function query_img_provider_stats( $_refresh = false ) { if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) { $url = ''; $stat_dom = 'https://no-cdn.shortpixel.ai/'; $endpoint = $stat_dom . 'read-domain/'; $domain = AUTOPTIMIZE_SITE_DOMAIN; // make sure parse_url result makes sense, keeping $url empty if not. if ( $domain && ! empty( $domain ) ) { $url = $endpoint . $domain; if ( true === $_refresh ) { $url = $url . '/refresh'; } } $url = apply_filters( 'autoptimize_filter_imgopt_stat_url', $url ); // only do the remote call if $url is not empty to make sure no parse_url // weirdness results in useless calls. if ( ! empty( $url ) ) { $response = wp_remote_get( $url ); if ( ! is_wp_error( $response ) ) { if ( '200' == wp_remote_retrieve_response_code( $response ) ) { $stats = json_decode( wp_remote_retrieve_body( $response ), true ); autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_provider_stat', $stats ); } } } } } public static function get_img_provider_stats() { // wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker. $self = new self(); return $self->query_img_provider_stats(); } /** * Determines and returns the service launch status. * * @return bool */ public function launch_ok() { static $launch_status = null; if ( null === $launch_status ) { $avail_imgopt = ''; if ( is_array( $this->options ) && array_key_exists( 'availabilities', $this->options ) && is_array( $this->options['availabilities'] ) && array_key_exists( 'extra_imgopt', $this->options['availabilities'] ) ) { $avail_imgopt = $this->options['availabilities']['extra_imgopt']; } $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 ); $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' ); $launch_status = false; if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) { $launch_status = true; if ( ! $has_launched ) { autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_launched', 'on' ); } } } return $launch_status; } public static function launch_ok_wrapper() { // needed for "plug" notice in autoptimizeMain.php. $self = new self(); return $self->launch_ok(); } public function get_imgopt_provider_userstatus() { static $_provider_userstatus = null; if ( is_null( $_provider_userstatus ) ) { $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' ); if ( is_array( $_stat ) ) { if ( array_key_exists( 'Status', $_stat ) ) { $_provider_userstatus['Status'] = $_stat['Status']; } else { // if no stats then we assume all is well. $_provider_userstatus['Status'] = 2; } if ( array_key_exists( 'timestamp', $_stat ) ) { $_provider_userstatus['timestamp'] = $_stat['timestamp']; } else { // if no timestamp then we return "". $_provider_userstatus['timestamp'] = ''; } } else { // no provider_stat yet, assume/ return all OK. $_provider_userstatus['Status'] = 2; $_provider_userstatus['timestamp'] = ''; } } return $_provider_userstatus; } } PK ��3\T�H�� � classes/static/toolbar.jsnu �[��� jQuery( document ).ready(function() { var percentage = jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar' ).attr('percentage'); var rotate = percentage * 1.8; jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({ '-webkit-transform' : 'rotate(' + rotate + 'deg)', '-ms-transform' : 'rotate(' + rotate + 'deg)', 'transform' : 'rotate(' + rotate + 'deg)' }); // Fix Background color of circle percentage & delete cache to fit with the current color theme jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .inset' ).css( 'background-color', jQuery( '#wp-admin-bar-autoptimize .ab-sub-wrapper' ).css( 'background-color') ); jQuery( '#wp-admin-bar-autoptimize-delete-cache .ab-item' ).css( 'background-color', jQuery( '#wpadminbar' ).css( 'background-color') ); jQuery( '#wp-admin-bar-autoptimize-default li' ).on('click', function(e) { var id = ( typeof e.target.id != 'undefined' && e.target.id ) ? e.target.id : jQuery( e.target ).parent( 'li' ).attr( 'id' ); var action = ''; if( id == 'wp-admin-bar-autoptimize-delete-cache' ){ action = 'autoptimize_delete_cache'; } else { return; } // Remove the class "hover" from drop-down Autoptimize menu to hide it. jQuery( '#wp-admin-bar-autoptimize' ).removeClass( 'hover' ); // Create and Show the Autoptimize Loading Modal var modal_loading = jQuery( '<div class="autoptimize-loading"></div>' ).appendTo( 'body' ).show(); var success = function() { // Reset output values & class names of cache info jQuery( '#wp-admin-bar-autoptimize-cache-info .size' ).attr( 'class', 'size green' ).html( '0.00 B' ); jQuery( '#wp-admin-bar-autoptimize-cache-info .files' ).html( '0' ); jQuery( '#wp-admin-bar-autoptimize-cache-info .percentage .numbers' ).attr( 'class', 'numbers green' ).html( '0%' ); jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).attr( 'class', 'fill bg-green' ); // Reset the class names of bullet icon jQuery( '#wp-admin-bar-autoptimize' ).attr( 'class', 'menupop bullet-green' ); // Reset the Radial Bar progress jQuery( '#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill' ).css({ '-webkit-transform' : 'rotate(0deg)', '-ms-transform' : 'rotate(0deg)', 'transform' : 'rotate(0deg)' }); }; var notice = function() { jQuery( '<div id="ao-delete-cache-timeout" class="notice notice-error is-dismissible"><p><strong><span style="display:block;clear:both;">' + autoptimize_ajax_object.error_msg + '</span></strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">' + autoptimize_ajax_object.dismiss_msg + '</span></button></div><br>' ).insertAfter( '#wpbody .wrap h1:first-of-type' ).show(); }; jQuery.ajax({ type : 'GET', url : autoptimize_ajax_object.ajaxurl, data : {'action':action, 'nonce':autoptimize_ajax_object.nonce}, dataType : 'json', cache : false, timeout : 9000, success : function( cleared ) { // Remove the Autoptimize Loading Modal modal_loading.remove(); if ( cleared ) { success(); } else { notice(); } }, error: function( jqXHR, textStatus ) { // Remove the Autoptimize Loading Modal modal_loading.remove(); // WordPress Admin Notice notice(); } }); }); }); PK ��3\�אh� � classes/static/toolbar.min.cssnu �[��� .autoptimize-loading{display:none;position:fixed;background-color:rgba(102,102,102,.8);background-image:url(loading.gif);background-position:center;background-repeat:no-repeat;top:0;left:0;width:100%;height:100%;z-index:9000000000}#wp-admin-bar-autoptimize .white{color:#eee}#wp-admin-bar-autoptimize .green{color:#26bd26}#wp-admin-bar-autoptimize .orange{color:#ec9103}#wp-admin-bar-autoptimize .red{color:#ea1919}#wp-admin-bar-autoptimize .bg-green{background:#26bd26}#wp-admin-bar-autoptimize .bg-orange{background:#ec9103}#wp-admin-bar-autoptimize .bg-red{background:#ea1919}#wp-admin-bar-autoptimize.bullet-green .ab-icon:before,#wp-admin-bar-autoptimize.bullet-green:hover .ab-icon:before{content:"\f159";color:#02ca02;font-size:14px}#wp-admin-bar-autoptimize.bullet-orange .ab-icon:before,#wp-admin-bar-autoptimize.bullet-orange:hover .ab-icon:before{content:"\f159";color:#ec9103;font-size:14px}#wp-admin-bar-autoptimize.bullet-red .ab-icon:before,#wp-admin-bar-autoptimize.bullet-red:hover .ab-icon:before{content:"\f159";color:#ea1919;font-size:14px;-webkit-animation:blink 1s step-end infinite;animation:blink 1s step-end infinite}@-webkit-keyframes blink{50%{visibility:hidden}}@keyframes blink{50%{visibility:hidden}}#wp-admin-bar-autoptimize table,#wp-admin-bar-autoptimize th,#wp-admin-bar-autoptimize td{border:0 !important}#wp-admin-bar-autoptimize-default{padding-top:0 !important}#wp-admin-bar-autoptimize-delete-cache .ab-item{cursor:pointer !important;background:#464b50}#wp-admin-bar-autoptimize-delete-cache .ab-item:hover{color:rgba(240,245,250,.85) !important;background:#b57373 !important}#wp-admin-bar-autoptimize-cache-info{padding-top:8px !important;padding-bottom:8px !important}#wp-admin-bar-autoptimize-cache-info,#wp-admin-bar-autoptimize-cache-info .ab-item{height:auto !important;cursor:default !important}#wp-admin-bar-autoptimize-cache-info td+td{padding-left:3px}#wp-admin-bar-autoptimize-cache-info .ab-item,#wp-admin-bar-autoptimize-cache-info .ab-item:hover{color:#b4b9be !important}#wp-admin-bar-autoptimize-cache-info .ab-item>p{display:block}#wp-admin-bar-autoptimize-cache-info .ab-item p,#wp-admin-bar-autoptimize-cache-info .ab-item td{font-size:11px !important;line-height:16px !important}#wp-admin-bar-autoptimize-cache-info .ab-item table{display:inline-block !important;margin-left:10px !important}.autoptimize-radial-bar{display:inline-block !important;margin-top:5px !important}.autoptimize-radial-bar,.autoptimize-radial-bar .mask,.autoptimize-radial-bar .fill,.autoptimize-radial-bar .shadow{width:36px !important;height:36px !important}.autoptimize-radial-bar{background-color:#d6dadc}.autoptimize-radial-bar .fill{background-color:#02ca02}.autoptimize-radial-bar .numbers{color:#02ca02}.autoptimize-radial-bar .mask{clip:rect(0px,36px,36px,18px)}.autoptimize-radial-bar .fill{clip:rect(0px,18px,36px,0px)}.autoptimize-radial-bar .inset{width:26px !important;height:26px !important;margin-left:5px !important;margin-top:5px !important;background-color:#32373c}.autoptimize-radial-bar .percentage{width:26px !important;height:16px !important;line-height:11px !important;top:7px !important;left:0 !important;overflow:hidden}.autoptimize-radial-bar .numbers{width:26px !important;font-weight:600 !important;font-size:9px !important;margin-top:-5px !important;display:inline-block;vertical-align:top;text-align:center}.autoptimize-radial-bar .inset{box-shadow:3px 3px 5px rgba(0,0,0,.3) !important}.autoptimize-radial-bar .shadow{box-shadow:3px 3px 5px rgba(0,0,0,.3) inset !important}.autoptimize-radial-bar .mask,.autoptimize-radial-bar .fill,.autoptimize-radial-bar .shadow,.autoptimize-radial-bar .inset,.autoptimize-radial-bar .percentage{position:absolute !important}.autoptimize-radial-bar,.autoptimize-radial-bar .mask,.autoptimize-radial-bar .fill,.autoptimize-radial-bar .shadow,.autoptimize-radial-bar .inset{border-radius:50% !important}#wp-admin-bar-autoptimize tr{border:0 !important}#wp-admin-bar-autoptimize td{background-color:#32373c !important} PK ��3\Oy�i_ _ classes/static/toolbar.min.jsnu �[��� jQuery(document).ready(function() {var percentage=jQuery('#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar').attr('percentage');var rotate=percentage*1.8;jQuery('#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill').css({'-webkit-transform':'rotate('+rotate+'deg)','-ms-transform':'rotate('+rotate+'deg)','transform':'rotate('+rotate+'deg)'});jQuery('#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .inset').css('background-color',jQuery('#wp-admin-bar-autoptimize .ab-sub-wrapper').css('background-color'));jQuery('#wp-admin-bar-autoptimize-delete-cache .ab-item').css('background-color',jQuery('#wpadminbar').css('background-color'));jQuery('#wp-admin-bar-autoptimize-default li').on('click',function(e) {var id=(typeof e.target.id!='undefined'&&e.target.id)?e.target.id:jQuery(e.target).parent('li').attr('id');var action='';if(id=='wp-admin-bar-autoptimize-delete-cache'){action='autoptimize_delete_cache';}else{return;} jQuery('#wp-admin-bar-autoptimize').removeClass('hover');var modal_loading=jQuery('<div class="autoptimize-loading"></div>').appendTo('body').show();var success=function(){jQuery('#wp-admin-bar-autoptimize-cache-info .size').attr('class','size green').html('0.00 B');jQuery('#wp-admin-bar-autoptimize-cache-info .files').html('0');jQuery('#wp-admin-bar-autoptimize-cache-info .percentage .numbers').attr('class','numbers green').html('0%');jQuery('#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill').attr('class','fill bg-green');jQuery('#wp-admin-bar-autoptimize').attr('class','menupop bullet-green');jQuery('#wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .mask.full, #wp-admin-bar-autoptimize-cache-info .autoptimize-radial-bar .fill').css({'-webkit-transform':'rotate(0deg)','-ms-transform':'rotate(0deg)','transform':'rotate(0deg)'});};var notice=function(){jQuery('<div id="ao-delete-cache-timeout" class="notice notice-error is-dismissible"><p><strong><span style="display:block;clear:both;">'+autoptimize_ajax_object.error_msg+'</span></strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">'+autoptimize_ajax_object.dismiss_msg+'</span></button></div><br>').insertAfter('#wpbody .wrap h1:first-of-type').show();};jQuery.ajax({type:'GET',url:autoptimize_ajax_object.ajaxurl,data:{'action':action,'nonce':autoptimize_ajax_object.nonce},dataType:'json',cache:false,timeout:9000,success:function(cleared) {modal_loading.remove();if(cleared){success();}else{notice();}},error:function(jqXHR,textStatus) {modal_loading.remove();notice();}});});}); PK ��3\4�' ' * classes/static/exit-survey/exit-survey.cssnu �[��� tr[data-slug="autoptimize"] span.deactivate{ position: relative; } .ao-feedback { background: #fff; max-width: 400px; z-index: 10000; box-shadow: 0 0 15px -5px rgba(0, 0, 0, .5); transition: all .3s ease-out; } .ao-feedback .popup--header { position: relative; background-color: #e5e5e5; } .ao-feedback .popup--header h5 { margin: 0; font-size: 16px; padding: 10px 15px; color: #222; font-weight: 900; text-align: left; } .ao-feedback .popup--body { padding: 15px; padding-top: 5px; } .ao-feedback .popup--form { margin: 0; font-size: 13px; padding-top: 10px; } .ao-feedback .popup--form input[type="radio"] { margin: 0 10px 0 0; } .ao-feedback .popup--form input[type="radio"]:checked ~ textarea { display: block; } .ao-feedback .popup--form textarea { width: 100%; margin: 10px 0 0; display: none; max-height: 150px; } .ao-feedback .popup--form input[type='email'] { width: 100%; margin: 10px 0 0; } .ao-feedback .popup--form input[type='email']:invalid { color:red; border-color:red; } .ao-feedback .popup--form p.last-attempt { display: none; } .ao-feedback li { display: flex; align-items: center; margin-bottom: 15px; flex-wrap: wrap; } .ao-feedback li label { max-width: 90%; } .ao-feedback li:last-child { margin-bottom: 0; } .ao-feedback .popup--footer { padding: 0 15px 15px; } .ao-feedback .actions { display: flex; flex-wrap: wrap; } .info-disclosure-link { width: 100%; margin-bottom: 15px; } .ao-feedback .info-disclosure-content { max-height: 0; overflow: hidden; width: 100%; transition: .3s ease; } .ao-feedback .info-disclosure-content.active { max-height: 300px; } .ao-feedback .info-disclosure-content p { margin: 0; } .ao-feedback .info-disclosure-content ul { margin: 10px 0; border-radius: 3px; } .ao-feedback .info-disclosure-content ul li { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0; padding: 5px 0; border-bottom: 1px solid #ccc; } .ao-feedback .buttons { display: flex; width: 100%; } .ao-feedback .buttons input:nth-child(2) { margin: auto; } .ao-feedback .buttons input:last-child { margin-left: auto; } .ao-plugin-uninstall-feedback-popup .popup--header:before { content: ""; display: block; position: absolute; border: 20px solid #e5e5e5; left: -10px; top: 50%; border-top: 20px solid transparent; border-bottom: 20px solid transparent; border-left: 0; transform: translateY(-50%); } .ao-plugin-uninstall-feedback-popup { display: none; position: absolute; white-space: normal; width: 400px; left: 122%; top: -21px; } .ao-plugin-uninstall-feedback-popup.sending-feedback .popup--body i { animation: rotation 2s infinite linear; display: block; float: none; align-items: center; width: 100%; margin: 0 auto; height: 100%; background: transparent; padding: 0; } .ao-plugin-uninstall-feedback-popup.sending-feedback .popup--body i:before { padding: 0; background: transparent; box-shadow: none; color: #b4b9be } .ao-plugin-uninstall-feedback-popup.active { display: block; } body.ao-feedback-open .ao-feedback-overlay { content: ""; display: block; background-color: rgba(0, 0, 0, 0.5); top: 0; bottom: 0; right: 0; left: 0; z-index: 10000; position: fixed; } @media (max-width: 768px) { .ao-plugin-uninstall-feedback-popup { position: fixed; max-width: 100%; margin: 0 auto; left: 50%; top: 50px; transform: translateX(-50%); } .ao-plugin-uninstall-feedback-popup .popup--header:before { display: none; } } PK ��3\��F F ) classes/static/exit-survey/exit-survey.jsnu �[��� (function ($) { $(document).ready(function () { var targetElement = 'tr[data-plugin="autoptimize/autoptimize.php"] span.deactivate a'; var redirectUrl = $(targetElement).attr('href'); if ($('.ao-feedback-overlay').length === 0) { $('body').prepend('<div class="ao-feedback-overlay"></div>'); } $('#ao_uninstall_feedback_popup').appendTo($(targetElement).parent()); $(targetElement).on('click', function (e) { e.preventDefault(); $('#ao_uninstall_feedback_popup ').addClass('active'); $('body').addClass('ao-feedback-open'); $('.ao-feedback-overlay').on('click', function () { $('#ao_uninstall_feedback_popup ').removeClass('active'); $('body').removeClass('ao-feedback-open'); }); }); $('#ao_uninstall_feedback_popup .info-disclosure-link').on('click', function (e) { e.preventDefault(); $(this).parent().find('.info-disclosure-content').toggleClass('active'); }); $('#ao_uninstall_feedback_popup input[type="radio"]').on('change', function () { var radio = $(this); $('p.last-attempt').hide(); if (radio.parent().find('textarea').length > 0 && radio.parent().find('textarea').val().length === 0) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').attr('disabled', 'disabled'); radio.parent().find('textarea').on('keyup', function (e) { if ($(this).val().length === 0) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').attr('disabled', 'disabled'); } else if ( $('#ao_feedback998')[0].checkValidity() == true ) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').removeAttr('disabled'); } }); } else { if ( $('#ao_feedback998')[0].checkValidity() == true ) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').removeAttr('disabled'); } $(this).siblings('p.last-attempt').show(); } }); $('#ao_feedback998').on('keyup', function (e) { email_node = $(this); email_val = email_node.val(); if ( email_val.length > 0 && email_node[0].checkValidity() == false ) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').attr('disabled', 'disabled'); } else if ( $( '#ao_uninstall_feedback_popup input[name="ao-deactivate-option"]:checked' ).length > 0 ) { $('#ao_uninstall_feedback_popup #ao-deactivate-yes').removeAttr('disabled'); } }); $('#ao_uninstall_feedback_popup #ao-deactivate-no').on('click', function (e) { e.preventDefault(); e.stopPropagation(); $(targetElement).unbind('click'); $('body').removeClass('ao-feedback-open'); $('#ao_uninstall_feedback_popup').remove(); if (redirectUrl !== '') { location.href = redirectUrl; } }); $('#ao_uninstall_feedback_popup #ao-deactivate-cancel').on('click', function (e) { e.preventDefault(); e.stopPropagation(); $('#ao_uninstall_feedback_popup ').removeClass('active'); $('body').removeClass('ao-feedback-open'); }); $('#ao_feedback_email_toggle').on('click', function (e) { $('#ao_feedback998').toggle(); }); $('#ao_uninstall_feedback_popup #ao-deactivate-yes').on('click', function (e) { e.preventDefault(); e.stopPropagation(); $(targetElement).unbind('click'); var modal_data = JSON.parse(atob($('#ao_uninstall_feedback_popup').data('modal'))) var selectedOption = $( '#ao_uninstall_feedback_popup input[name="ao-deactivate-option"]:checked' ); var reason; if( selectedOption.attr("id") === "ao_feedback999" ){ reason = 'Other: ' + selectedOption.parent().find('textarea').val().trim() }else{ reason = selectedOption.parent().find('label').attr('data-reason').trim() } var data = { 'url': modal_data.home, 'reason': reason, 'type': 'WP ' + $('#core_version').text().trim(), 'version' : 'AO ' + $('#ao_plugin_version').text().trim(), 'email': $('#ao_feedback998').val().trim(), }; $.ajax({ type: 'POST', url: atob( modal_data.dest ), data: data, complete() { $('body').removeClass('ao-feedback-open'); $('#ao_uninstall_feedback_popup').remove(); if (redirectUrl !== '') { location.href = redirectUrl; } }, beforeSend() { $('#ao_uninstall_feedback_popup').addClass('sending-feedback'); $('#ao_uninstall_feedback_popup .popup--footer').remove(); $('#ao_uninstall_feedback_popup .popup--body').html('<i class="dashicons dashicons-update-alt"></i>'); } }); }); }); })(jQuery); PK ��3\*�pƵ � classes/static/toolbar.cssnu �[��� /* Loading Modal */ .autoptimize-loading { display: none; position: fixed; background-color: rgba(102, 102, 102, 0.8); background-image: url('loading.gif'); background-position: center; background-repeat: no-repeat; top: 0; left: 0; width: 100%; height: 100%; z-index: 9000000000; } /* Toolbar Font Colors */ #wp-admin-bar-autoptimize .white { color: #EEE; } #wp-admin-bar-autoptimize .green { color: #26BD26; } #wp-admin-bar-autoptimize .orange { color: #EC9103; } #wp-admin-bar-autoptimize .red { color: #EA1919; } #wp-admin-bar-autoptimize .bg-green { background: #26BD26; } #wp-admin-bar-autoptimize .bg-orange { background: #EC9103; } #wp-admin-bar-autoptimize .bg-red { background: #EA1919; } /* Toolbar Bullet Icons */ #wp-admin-bar-autoptimize.bullet-green .ab-icon::before, #wp-admin-bar-autoptimize.bullet-green:hover .ab-icon::before { content: "\f159"; color: #02CA02; font-size: 14px; } #wp-admin-bar-autoptimize.bullet-orange .ab-icon::before, #wp-admin-bar-autoptimize.bullet-orange:hover .ab-icon::before { content: "\f159"; color: #EC9103; font-size: 14px; } #wp-admin-bar-autoptimize.bullet-red .ab-icon::before, #wp-admin-bar-autoptimize.bullet-red:hover .ab-icon::before { content: "\f159"; color: #EA1919; font-size: 14px; -webkit-animation: blink 1s step-end infinite; animation: blink 1s step-end infinite; } @-webkit-keyframes blink { 50% { visibility: hidden; }} @keyframes blink { 50% { visibility: hidden; }} /* Some cosmetic Toolbar things */ #wp-admin-bar-autoptimize table, #wp-admin-bar-autoptimize th, #wp-admin-bar-autoptimize td { border: 0px !important; } #wp-admin-bar-autoptimize-default { padding-top: 0 !important; } #wp-admin-bar-autoptimize-delete-cache .ab-item { cursor: pointer !important; background: #464b50; } #wp-admin-bar-autoptimize-delete-cache .ab-item:hover { color: rgba(240,245,250,0.85) !important; background: #B57373 !important; } #wp-admin-bar-autoptimize-cache-info { padding-top: 8px !important; padding-bottom: 8px !important; } #wp-admin-bar-autoptimize-cache-info, #wp-admin-bar-autoptimize-cache-info .ab-item { height: auto !important; cursor: default !important; } #wp-admin-bar-autoptimize-cache-info td + td { padding-left: 3px; } #wp-admin-bar-autoptimize-cache-info .ab-item, #wp-admin-bar-autoptimize-cache-info .ab-item:hover { color: #b4b9be !important; } #wp-admin-bar-autoptimize-cache-info .ab-item > p { display: block; } #wp-admin-bar-autoptimize-cache-info .ab-item p, #wp-admin-bar-autoptimize-cache-info .ab-item td { font-size: 11px !important; line-height: 16px !important; } #wp-admin-bar-autoptimize-cache-info .ab-item table { display: inline-block !important; margin-left: 10px !important; } /* Radial Bar */ .autoptimize-radial-bar { display: inline-block !important; margin-top: 5px !important; } .autoptimize-radial-bar, .autoptimize-radial-bar .mask, .autoptimize-radial-bar .fill, .autoptimize-radial-bar .shadow { width : 36px !important; height : 36px !important; } .autoptimize-radial-bar { background-color : #d6dadc; } .autoptimize-radial-bar .fill { background-color : #02ca02; } .autoptimize-radial-bar .numbers { color : #02ca02; } .autoptimize-radial-bar .mask { clip : rect(0px, 36px, 36px, 18px); } .autoptimize-radial-bar .fill { clip : rect(0px, 18px, 36px, 0px); } .autoptimize-radial-bar .inset { width : 26px !important; height : 26px !important; margin-left : 5px !important; margin-top : 5px !important; background-color : #32373c; } .autoptimize-radial-bar .percentage { width : 26px !important; height : 16px !important; line-height : 11px !important; top : 7px !important; left : 0px !important; overflow : hidden; } .autoptimize-radial-bar .numbers { width : 26px !important; font-weight : 600 !important; font-size : 9px !important; margin-top : -5px !important; display : inline-block; vertical-align : top; text-align : center; } .autoptimize-radial-bar .inset { box-shadow : 3px 3px 5px rgba(0,0,0,0.3) !important; } .autoptimize-radial-bar .shadow { box-shadow : 3px 3px 5px rgba(0,0,0,0.3) inset !important; } .autoptimize-radial-bar .mask, .autoptimize-radial-bar .fill, .autoptimize-radial-bar .shadow, .autoptimize-radial-bar .inset, .autoptimize-radial-bar .percentage { position : absolute !important; } .autoptimize-radial-bar, .autoptimize-radial-bar .mask, .autoptimize-radial-bar .fill, .autoptimize-radial-bar .shadow, .autoptimize-radial-bar .inset { border-radius : 50% !important; } /* fixes for toolbar on frontend for other themes messing things up */ #wp-admin-bar-autoptimize tr{border:0 !important} #wp-admin-bar-autoptimize td{background-color:#32373c !important} PK ��3\Z�j classes/static/loading.gifnu �[��� GIF89aX X � O�Ϻ�n������ !�NETSCAPE2.0 !�XMP DataXMP<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.0-c061 64.140949, 2010/12/07-10:57:01 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmpMM:OriginalDocumentID="xmp.did:57E0EBF072226811BD6584DB68DC4565" xmpMM:DocumentID="xmp.did:BB499BE6526A11E19592A88DB5429835" xmpMM:InstanceID="xmp.iid:BB499BE5526A11E19592A88DB5429835" xmp:CreatorTool="Adobe Photoshop CS5.1 Macintosh"> <xmpMM:DerivedFrom stRef:instanceID="xmp.iid:FCAFA0629E226811BD6584DB68DC4565" stRef:documentID="xmp.did:57E0EBF072226811BD6584DB68DC4565"/> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?>�������������������������������������������������������������������������������������������������������������������������������~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"! !� , X X �H����IY�8�z��^(:�If��¶0���KӶ���n���7ƀ"�ѣd��gO 57�*%��jeA��BM�ǵ�mV[���Y��y�q�nw��}.�X��{ �U���~x�}�i�����������������������������������������ø����ɳ�Ǟ����������������ܾ�������7��������������5��WL�ja�w��7�a��D&����G�1Ѹ�ETI�\ɲe) 0cʜI�f8s��ɳg� @� J�hͣHe��ɴiΟE�J ����N��,0��Q�`a.�JV T�h� ;�lֳi����mS�q�εZ��ּ^�V��w'^�D'%\�)W�ze���c�_%Ӥ�0f���Vf�s��XG�,���L΅YCv�4�j��ӎ �on���ھ��w�� z�5�r���:N<:���q_�,{��۹��������>/7�w��z��~��#�.O6� !� , X : ���%�I��$�ͻ`�\dIyh��,d��*m���9�m���s�]�u�%gKV��EE�WUu eM�T�-�QcW�r��Gkv��n��sM~��{7}~����=������B�� ������������������{�����u�����������������������ξ�ѻ�������������������������������������m���?r��f� �� �-���!�rN�V�z�;��m���"Đ�F��X�$J�$ñ,�2$L^%��xs�̙�vF�+�A� ��� 4R�J��T_ԩ��ʻʴ��x\��rYX�NɖM���� �v w�\�i�2;��.7�b�j$궝`m !� , X X ���%�I��8��;�`(f^ �h��좾�Զq�ά������^ H�;�d�T����U���n�.� �� s P��n;���o�;ʮ� �$y�+��A�����I�����������������������������������������������ŧ���ˑ��������ֿؼڹܶ��䦴��������������� �H�ݼ|�����~#�+����3 �ȑ��A� 0�H�@ǎCVY2�I�)U&d���K�1e^���fĜ:��� �gA�Ab$j��@�IE.e��)<�I�R�gubT�Z�v�J�+��TǾ�-S�˚��(�vlu��yףܹ��� �L�- V���⿀�|��ԭ�(W|3�CJ� ���.Ko���ͨ������ k7L !� , : X �(����I�����"�`ō���.�N�ھh��th�x��/����戄)K���lN����ڨ"����f�ǀ��;T�>7<'?���dyN��{vZ~�y�h�c�����������������������������������������������������������Ŏǣ��˞͍���ӝ��כ����߰������������������������� H�`*\Ȱa��lH�b ���raƏ 'vI $H�$9���2eŕ[���̙kF���·<{���Q(E�E�2DJ0hO���*q�ҜTCZ��3�ԙY�rUv�W�eϦL�u,۱]��%��P�m�օ��mع# !� , X X �����I��8�ͻ��#�L��h��lˑ0$���Y��[n��5�W��)�Ռ=�'�4T%]���6��Y��U}��Ֆ��sj����{|gw*jy� }ps�%��A���=���k� �h�c��`�[��X�S����K���D��P�d��~����q�����L�ɓ�:���l���-������������������������������� ��.�Ap \�-�@�8����~^ė���{ ~�2��%����r��w-U�,s�L�5��d�S��=u��o(Qs?�"5�T Ӧ�B'u*§V�aͺ�*ׯ`ê#@��ٳhӊݖ��[�k����6n�x�ڽ��~���w���"N�v1c��7�,r��gW�,��cόA'm��`ӀQ�U��u�˘�R�횰� !� , X : �8����I��8�ͻ��#�L��h��lˑ0$���Y��[n��5�W��)�Ռ=�'�4T%]���6��Y��U}��Ֆ��sj����{|gw*jy� }ps�%��A���=���k� �h�c��`�[��X�S����K���D��P�d��~����q�����L�ɓ�:���l���-������������������������� ����������� xϟAy �\��Cv 2�X��È�(R��s�7�9�� $C�Iv3��?��Xt��6�i� �@�y�l��C�}wi҂K�5} 5*��T+Z�z4�V�X�n�*��ذT�v5��S�eŶ]+,ݴs��m^�^$ !� , X X �H����I��8�ͻ��#�L��h��lˑ0$���Y��[n��5�W��)�Ռ=�'�4T%]���6��Y��U}��Ֆ��sj����{|gw*jy� }ps�%��A���=���k� �h�c��`�[��X�S����K���D��P�d��~����q�����L�ɓ�:���l���-������������������������������� ��.��wj;xP�B�&�P"A� -ĸO��?��<��O�=�M�C9Oe;��\�� O�:�5m�ÉP':�|��)�Т��"%wt鸦N�A��m*Ղ8����u�Ү`Ê=��ٳhӪ�M�۷g�F�Kw�ܺx��-�7�x��+x���M|�.c�cC+9-�� .W�,��cόA'm��`ӀQ�U��1沬�~�n !� , : X �H����I�����"�`ō���.�N�ھh��th�x��/����戄)K���lN����ڨ"����f�ǃ��;T�>7<'?���dyN��{vZ~�y�h�c���������������������������������������������������������ÍŦ��ɭ����Ѡ�ԟ��ز����ߜ����������������������� � H0���*\Ȑ�Ç 2�H!ċT��q��9���cȑKz<���J�,[v|�0�L�4!ڼi1�Ý<I��t�P�E��R�Mo>��1)Ω �Z�5�L�Y�&�kK�fQ��*v�X�Sӎt�VhW�[����\� ;PK ��3\?����� �� classes/autoptimizeConfig.phpnu �[��� <?php /** * Main configuration logic. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeConfig { /** * Options. * * @var array */ private $config = null; /** * Singleton instance. * * @var self|null */ static private $instance = null; /** * Options. * * @var bool */ private $settings_screen_do_remote_http = true; /** * Singleton. */ private function __construct() { if ( is_admin() ) { // Add the admin page and settings. if ( autoptimizeOptionWrapper::is_ao_active_for_network() ) { add_action( 'network_admin_menu', array( $this, 'addmenu' ) ); } add_action( 'admin_menu', array( $this, 'addmenu' ) ); add_action( 'admin_init', array( $this, 'registersettings' ) ); add_action( 'admin_init', array( 'PAnD', 'init' ) ); // Set meta info. if ( function_exists( 'plugin_row_meta' ) ) { // 2.8 and higher. add_filter( 'plugin_row_meta', array( $this, 'setmeta' ), 10, 2 ); } elseif ( function_exists( 'post_class' ) ) { // 2.7 and lower. $plugin = plugin_basename( AUTOPTIMIZE_PLUGIN_DIR . 'autoptimize.php' ); add_filter( 'plugin_action_links_' . $plugin, array( $this, 'setmeta' ) ); } // Clean cache? if ( autoptimizeOptionWrapper::get_option( 'autoptimize_cache_clean' ) ) { autoptimizeCache::clearall(); autoptimizeOptionWrapper::update_option( 'autoptimize_cache_clean', 0 ); } $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http ); if ( $this->is_ao_meta_settings_active() ) { $meta_box = new autoptimizeMetabox(); } } // Adds the Autoptimize Toolbar to the Admin bar. // (we load outside the is_admin check so it's also displayed on the frontend toolbar). $toolbar = new autoptimizeToolbar(); } /** * Instantiates aoconfig. * * @return autoptimizeConfig */ static public function instance() { // Only one instance. if ( null === self::$instance ) { self::$instance = new autoptimizeConfig(); } return self::$instance; } public function show_network_message() { ?> <div class="wrap"> <h1><?php esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1> <?php echo $this->ao_admin_tabs(); ?> <p style="font-size:120%;"><?php echo apply_filters( 'autoptimize_filter_settingsscreen_multisite_network_message', esc_html__( 'Autoptimize is enabled and configured on a WordPress network level. Please contact your network administrator if you need Autoptimize settings changed.', 'autoptimize' ) ); ?></p> </div> <?php } public function show_config() { // phpcs:disable Generic.WhiteSpace.ScopeIndent.IncorrectExact // phpcs:disable Generic.WhiteSpace.ScopeIndent.Incorrect $conf = self::instance(); ?> <style> /* title and button */ #ao_title_and_button:after {content:''; display:block; clear:both;} /* form */ .itemDetail { background: #fff; border: 1px solid #ccc; padding: 15px; margin: 15px 10px 10px 0; } .itemTitle { margin-top: 0; } .form-table th{font-weight:normal;} #autoptimize_main form input:invalid {box-shadow: 0 0 1px 1px red;} #autoptimize_main .cb_label {display: block; padding-left: 25px; text-indent: -25px;} #autoptimize_main .form-table th {padding-top: 15px; padding-bottom: 15px;} #autoptimize_main .js_aggregate td, #autoptimize_main .js_aggregate th, #autoptimize_main .js_not_aggregate td, #autoptimize_main .js_not_aggregate th{padding-top:0px;} /* rss block */ #futtta_feed ul{list-style:outside;} #futtta_feed {font-size:medium; margin:0px 20px;} /* banner + unslider */ .autoptimize_banner { margin: 0 38px; padding-bottom: 5px; } .autoptimize_banner ul li { font-size:medium; text-align:center; } .unslider { position:relative; } .unslider-arrow { display: block; left: unset; margin-top: -35px; margin-left: 7px; margin-right: 7px; border-radius: 32px; background: rgba(0, 0, 0, 0.10) no-repeat 50% 50%; color: rgba(255, 255, 255, 0.8); font: normal 20px/1 dashicons; speak: none; padding: 3px 2px 3px 4px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .unslider-arrow:hover { background-color: rgba(0, 0, 0, 0.20); color: #FFF; } .unslider-arrow.prev { padding: 3px 4px 3px 2px; } .unslider-arrow.next { right: 0px; } .unslider-arrow.prev::before { content: "\f341"; } .unslider-arrow.next::before { content: "\f345"; } /* responsive stuff: hide admin-feed on smaller screens */ @media (min-width: 961px) { #autoptimize_main {float:left;width:69%;} #autoptimize_admin_feed{float:right;width:30%;display:block !important;} } @media (max-width: 960px) { #autoptimize_main {width:100%;} #autoptimize_admin_feed {width:0%;display:none !important;} } @media (max-width: 782px) { #autoptimize_main input[type="checkbox"] {margin-left: 10px;} #autoptimize_main .cb_label {display: block; padding-left: 45px; text-indent: -45px;} } </style> <div class="wrap"> <div id="autoptimize_main"> <h1 id="ao_title"><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html_e( 'Autoptimize Pro Settings', 'autoptimize' ) : esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1> <?php echo $this->ao_admin_tabs(); ?> <form method="post" action="<?php echo admin_url( 'options.php' ); ?>"> <?php settings_fields( 'autoptimize' ); ?> <ul> <?php // Only show enable site configuration in network site option. if ( is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) { ?> <li class="itemDetail multiSite"> <h2 class="itemTitle"><?php esc_html_e( 'Multisite Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Enable site configuration?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" id="autoptimize_enable_site_config" name="autoptimize_enable_site_config" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_enable_site_config' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Enable Autoptimize configuration per site.', 'autoptimize' ); ?></label></td> </tr> </table> </li> <?php } else { ?> <input type="hidden" id="autoptimize_enable_site_config" name="autoptimize_enable_site_config" value="on" /> <?php } ?> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'JavaScript Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Optimize JavaScript Code?', 'autoptimize' ); ?></th> <td><input type="checkbox" id="autoptimize_js" name="autoptimize_js" <?php echo $conf->get( 'autoptimize_js' ) ? 'checked="checked" ' : ''; ?>/></td> </tr> <tr valign="top" class="js_sub js_aggregate_master"> <th scope="row"><?php esc_html_e( 'Aggregate JS-files?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_aggregate" name="autoptimize_js_aggregate" <?php echo $conf->get( 'autoptimize_js_aggregate' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Aggregate all linked JS-files to have them loaded non-render blocking?', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="js_sub js_aggregate hidden"> <th scope="row"> <?php esc_html_e( 'Also aggregate inline JS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo $conf->get( 'autoptimize_js_include_inline' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Let Autoptimize also extract JS from the HTML (discouraged as it can make Autoptimize\'s cache size grow quickly)', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="js_sub js_aggregate hidden"> <th scope="row"> <?php esc_html_e( 'Force JavaScript in <head>?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_forcehead" <?php echo $conf->get( 'autoptimize_js_forcehead' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Load JavaScript early (discouraged as it makes the JS render blocking)', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="js_sub js_aggregate hidden"> <th scope="row"> <?php esc_html_e( 'Add try-catch wrapping?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_trycatch" <?php echo $conf->get( 'autoptimize_js_trycatch' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'If your aggregated scripts break because of a JS-error, you might want to try this, but generally discouraged.', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="js_sub js_not_aggregate_master"> <th scope="row"><?php esc_html_e( 'Do not aggregate but defer?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_defer_not_aggregate" name="autoptimize_js_defer_not_aggregate" <?php echo $conf->get( 'autoptimize_js_defer_not_aggregate' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Individual JS-files will be minified and deferred, making them non-render-blocking.', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" id="js_defer_inline" class="js_sub js_not_aggregate hidden"> <th scope="row"> <?php esc_html_e( 'Also defer inline JS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_defer_inline" <?php echo $conf->get( 'autoptimize_js_defer_inline' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Also defer inline JS. Generally this will allow all JS to be deferred, so you should remove default exclusions, test and only exclude specific items if still needed.', 'autoptimize' ); ?></label></td> </tr> <?php if ( autoptimizeOptionWrapper::get_option( 'autoptimize_js_justhead' ) ) { ?> <tr valign="top" class="js_sub js_aggregate"> <th scope="row"> <?php esc_html_e( 'Look for scripts only in <head>?', 'autoptimize' ); echo ' <i>' . esc_html__( '(deprecated)', 'autoptimize' ) . '</i>'; ?> </th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_justhead" <?php echo $conf->get( 'autoptimize_js_justhead' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Mostly useful in combination with previous option when using jQuery-based templates, but might help keeping cache size under control.', 'autoptimize' ); ?></label></td> </tr> <?php } ?> <tr valign="top" class="js_sub"> <th scope="row"><?php esc_html_e( 'Exclude scripts from Autoptimize:', 'autoptimize' ); ?></th> <td><label><input type="text" pattern="[^\*]*" style="width:100%;" name="autoptimize_js_exclude" value="<?php echo esc_attr( autoptimizeOptionWrapper::get_option( 'autoptimize_js_exclude', '' ) ); ?>"/><br /> <?php echo esc_html__( 'A comma-separated list of scripts you do not want optimized, for example \'whatever.js, my_var\' (without the quotes).', 'autoptimize' ) . ' ' . esc_html__( 'Important: when "aggregate JS-files" is on, excluded non-minified files are still minified by Autoptimize unless that option under "misc" is disabled.', 'autoptimize' ); ?> </label></td> </tr> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Remove Unused JavaScript?', 'autoptimize' ); ?></th> <td><?php esc_html_e( 'Autoptimize combines your theme & plugins\' JavaScript, but does not know what is used and what not. If Google Pagespeed Insights detects unused JavaScript, consider using a plugin like "Plugin Organizer" or similar to manage what JavaScript is added where.', 'autoptimize' ); ?></td> </tr> </table> </li> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'CSS Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Optimize CSS Code?', 'autoptimize' ); ?></th> <td><input type="checkbox" id="autoptimize_css" name="autoptimize_css" <?php echo $conf->get( 'autoptimize_css' ) ? 'checked="checked" ' : ''; ?>/></td> </tr> <tr class="css_sub" valign="top"> <th scope="row"><?php esc_html_e( 'Aggregate CSS-files?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" id="autoptimize_css_aggregate" name="autoptimize_css_aggregate" <?php echo $conf->get( 'autoptimize_css_aggregate' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Aggregate all linked CSS-files? If this option is off, the individual CSS-files will remain in place but will be minified.', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="css_sub css_aggregate"> <th scope="row"><?php esc_html_e( 'Also aggregate inline CSS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_include_inline" <?php echo $conf->get( 'autoptimize_css_include_inline', '1' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Check this option for Autoptimize to also aggregate CSS in the HTML.', 'autoptimize' ); ?></label></td> </tr> <tr class="css_sub css_aggregate" valign="top"> <th scope="row"><?php esc_html_e( 'Generate data: URIs for images?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_datauris" <?php echo $conf->get( 'autoptimize_css_datauris' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Enable this to include small background-images in the CSS itself instead of as separate downloads.', 'autoptimize' ); ?></label></td> </tr> <?php if ( autoptimizeOptionWrapper::get_option( 'autoptimize_css_justhead' ) ) { ?> <tr valign="top" class="css_sub css_aggregate"> <th scope="row"> <?php esc_html_e( 'Look for styles only in <head>?', 'autoptimize' ); echo ' <i>' . esc_html__( '(deprecated)', 'autoptimize' ) . '</i>'; ?> </th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_justhead" <?php echo $conf->get( 'autoptimize_css_justhead' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Don\'t autoptimize CSS outside the head-section. If the cache gets big, you might want to enable this.', 'autoptimize' ); ?></label></td> </tr> <?php } ?> <tr valign="top" class="css_sub"> <th scope="row"><?php esc_html_e( 'Eliminate render-blocking CSS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_defer" id="autoptimize_css_defer" <?php echo $conf->get( 'autoptimize_css_defer' ) ? 'checked="checked" ' : ''; ?>/> <?php _e( 'Inline "above the fold CSS" while loading the main autoptimized CSS only after page load. <a href="https://wordpress.org/plugins/autoptimize/faq/" target="_blank">Check the FAQ</a> for more info.', 'autoptimize' ); echo ' '; $critcss_settings_url = get_admin_url( null, 'options-general.php?page=ao_critcss' ); // translators: links "autoptimize critical CSS" tab. echo sprintf( esc_html__( 'You can manually create rules for different types of pages or have this done fully automated on the %s tab.', 'autoptimize' ), '<a href="' . $critcss_settings_url . '">CriticalCSS</a>' ); ?> </label></td> </tr> <tr valign="top" class="css_sub" id="autoptimize_css_defer_inline"> <th scope="row"></th> <td><label><textarea rows="10" cols="10" style="width:100%;" spellcheck="false" placeholder="<?php esc_html_e( 'Paste the above the fold CSS here. You can leave this empty when using the automated Critical CSS integration.', 'autoptimize' ); ?>" name="autoptimize_css_defer_inline"><?php echo autoptimizeStyles::sanitize_css( autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer_inline' ) ); ?></textarea></label></td> </tr> <tr valign="top" class="css_sub css_aggregate"> <th scope="row"><?php esc_html_e( 'Inline all CSS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" id="autoptimize_css_inline" name="autoptimize_css_inline" <?php echo $conf->get( 'autoptimize_css_inline' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Inlining all CSS is an easy way to stop the CSS from being render-blocking, but is generally not recommended because the size of the HTML increases significantly. Additionally it might push meta-tags down to a position where e.g. Facebook and Whatsapp will not find them any more, breaking thumbnails when sharing.', 'autoptimize' ); ?></label></td> </tr> <tr valign="top" class="css_sub"> <th scope="row"><?php esc_html_e( 'Exclude CSS from Autoptimize:', 'autoptimize' ); ?></th> <td><label><input type="text" pattern="[^\*]*" style="width:100%;" name="autoptimize_css_exclude" value="<?php echo esc_attr( $conf->get( 'autoptimize_css_exclude', '' ) ); ?>"/><br /> <?php echo esc_html__( 'A comma-separated list of CSS you want to exclude from being optimized.', 'autoptimize' ) . ' ' . esc_html__( 'Important: excluded non-minified files are still minified by Autoptimize unless that option under "misc" is disabled.', 'autoptimize' ); ?> </label></td> </tr> <?php $_availabilities = autoptimizeOptionWrapper::get_option( 'autoptimize_service_availablity' ); if ( empty( $_availabilities ) || ! is_array( $_availabilities ) || ! array_key_exists( 'rapidload', $_availabilities ) || ! array_key_exists( 'status', $_availabilities['rapidload'] ) ) { $rapidload_true = true; } else if ( $_availabilities['rapidload']['status'] === 'up' ) { $rapidload_true = true; } else if ( $_availabilities['rapidload']['status'] !== 'up' ) { $rapidload_true = false; } else { $rapidload_true = false; } ?> <?php if ( $rapidload_true && false === autoptimizeUtils::is_plugin_active( 'unusedcss/unusedcss.php' ) ) { ?> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Remove Unused CSS?', 'autoptimize' ); ?></th> <?php $_rapidload_link = 'https://misc.optimizingmatters.com/partners/?from=csssettings&partner=rapidload'; ?> <td><?php // translators: a link to rapidload + strong tags echo sprintf( esc_html__( 'If Google Pagespeed Insights detects unused CSS, consider using %1$sthe premium Rapidload service%2$s to %3$sreduce your site\'s CSS size to up to 90%%4$s, resulting in a slimmer, faster site!', 'autoptimize' ), '<a href="' . $_rapidload_link . '" target="_blank">', '</a>', '<strong>', '</strong>' ); ?></td> </tr> <?php } ?> </table> </li> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'HTML Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Optimize HTML Code?', 'autoptimize' ); ?></th> <td><input type="checkbox" id="autoptimize_html" name="autoptimize_html" <?php echo $conf->get( 'autoptimize_html' ) ? 'checked="checked" ' : ''; ?>/></td> </tr> <tr class="html_sub" valign="top"> <th scope="row"><?php esc_html_e( 'Also minify inline JS/ CSS?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_html_minify_inline" <?php echo $conf->get( 'autoptimize_html_minify_inline' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Enable this if you want inline JS or CSS to be minified as well.', 'autoptimize' ); ?></label></td> </tr> <tr class="html_sub" valign="top"> <th scope="row"><?php esc_html_e( 'Keep HTML comments?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_html_keepcomments" <?php echo $conf->get( 'autoptimize_html_keepcomments' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Enable this if you want HTML comments to remain in the page.', 'autoptimize' ); ?></label></td> </tr> </table> </li> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'CDN Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'CDN Base URL', 'autoptimize' ); ?></th> <?php if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'autoptimize_filter_cdn_set_by_imgopt', false ) ) { // cdn set by imgopt, not to be changealbe in the settings. $cdn_editable = 'disabled'; $cdn_placeholder = 'placeholder="' . esc_html__( 'The CDN has automatically been set to make use of the image optimization CDN.', 'autoptimize' ) . ' "'; $cdn_description = ''; } else { $cdn_editable = ''; $cdn_placeholder = 'placeholder="' . esc_html__( 'example: //cdn.yoursite.com/', 'autoptimize' ) . ' "'; $cdn_description = esc_html__( 'Enter your CDN root URL to enable CDN for Autoptimized files. The URL can be http, https or protocol-relative. This is not needed for Cloudflare.', 'autoptimize' ); } ?> <td><label><input id="cdn_url" type="text" name="autoptimize_cdn_url" pattern="^(https?:)?\/\/([\da-z\.-]+)\.([\da-z\.]{2,6})([\/\w \.-]*)*(:\d{2,5})?\/?$" style="width:100%" <?php echo $cdn_placeholder . $cdn_editable; ?> value="<?php echo esc_url( autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' ), array( 'http', 'https' ) ); ?>" /><br /> <?php echo $cdn_description; ?> </label></td> </tr> </table> </li> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'Cache Info', 'autoptimize' ); ?></h2> <table class="form-table" > <tr valign="top" > <th scope="row"><?php esc_html_e( 'Cache folder', 'autoptimize' ); ?></th> <td><?php echo htmlentities( AUTOPTIMIZE_CACHE_DIR ); ?></td> </tr> <tr valign="top" > <th scope="row"><?php esc_html_e( 'Can we write?', 'autoptimize' ); ?></th> <td><?php echo ( autoptimizeCache::cacheavail() ? esc_html__( 'Yes', 'autoptimize' ) : esc_html__( 'No', 'autoptimize' ) ); ?></td> </tr> <tr valign="top" > <th scope="row"><?php esc_html_e( 'Cached styles and scripts', 'autoptimize' ); ?></th> <td> <?php $ao_stat_arr = autoptimizeCache::stats(); if ( ! empty( $ao_stat_arr ) && is_array( $ao_stat_arr ) ) { $ao_cache_size = size_format( $ao_stat_arr[1], 2 ); $details = ''; if ( $ao_cache_size > 0 ) { $details = ', ~' . $ao_cache_size . ' total'; } // translators: Kilobytes + timestamp shown. printf( esc_html__( '%1$s files, totalling %2$s (calculated at %3$s)', 'autoptimize' ), $ao_stat_arr[0], $ao_cache_size, wp_date( 'H:i', $ao_stat_arr[2] ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date } ?> </td> </tr> </table> </li> <li class="itemDetail"> <h2 class="itemTitle"><?php esc_html_e( 'Misc Options', 'autoptimize' ); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Save aggregated script/css as static files?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo $conf->get( 'autoptimize_cache_nogzip' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.', 'autoptimize' ); ?></label></td> </tr> <?php $_min_excl_class = ''; if ( ! $conf->get( 'autoptimize_css_aggregate' ) && ! $conf->get( 'autoptimize_js_aggregate' ) ) { $_min_excl_class = 'hidden'; } ?> <tr valign="top" id="min_excl_row" class="<?php echo $_min_excl_class; ?>"> <th scope="row"><?php esc_html_e( 'Minify excluded CSS and JS files?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_minify_excluded" <?php echo $conf->get( 'autoptimize_minify_excluded' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'When aggregating JS or CSS, excluded files that are not minified (based on filename) are by default minified by Autoptimize despite being excluded. Uncheck this option if anything breaks despite excluding.', 'autoptimize' ); ?></label></td> </tr> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Enable 404 fallbacks?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_fallback" <?php echo $conf->get( 'autoptimize_cache_fallback' ) ? 'checked="checked" ' : ''; ?>/> <?php // translators; just 2 opening and closing <code> tags. printf( esc_html__( 'Sometimes Autoptimized JS/ CSS is referenced in cached HTML but is already removed, resulting in broken sites. With this option on, Autoptimize will try to redirect those not-found files to "fallback"-versions, keeping the page/ site somewhat intact. In some cases this will require extra web-server level configuration to ensure %1$swp-content/autoptimize_404_handler.php%2$s is set to handle 404\'s in %1$swp-content/cache/autoptimize%2$s.', 'autoptimize' ), '<code>', '</code>' ); ?> </label></td> </tr> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Also optimize for logged in editors/ administrators?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_logged" <?php echo $conf->get( 'autoptimize_optimize_logged' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'By default Autoptimize is also active for logged on editors/ administrators, uncheck this option if you don\'t want Autoptimize to optimize when logged in e.g. to use a pagebuilder.', 'autoptimize' ); ?></label></td> </tr> <?php if ( function_exists( 'is_checkout' ) || function_exists( 'is_cart' ) || function_exists( 'edd_is_checkout' ) || function_exists( 'wpsc_is_cart' ) || function_exists( 'wpsc_is_checkout' ) ) { ?> <tr valign="top" > <th scope="row"><?php esc_html_e( 'Also optimize shop cart/ checkout?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_checkout" <?php echo $conf->get( 'autoptimize_optimize_checkout' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'By default Autoptimize is also active on your shop\'s cart/ checkout, uncheck not to optimize those.', 'autoptimize' ); ?></label> </td> </tr> <?php } ?> <?php if ( true === apply_filters( 'autoptimize_filter_enable_meta_ao_settings', true ) ) { ?> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Enable configuration per post/ page?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_enable_meta_ao_settings" <?php echo $conf->get( 'autoptimize_enable_meta_ao_settings' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Add a "metabox" to the post/ page edit screen allowing different optimizations to be turned off on a per post/ page level?', 'autoptimize' ); ?></label></td> </tr> <?php } ?> <tr valign="top"> <th scope="row"><?php esc_html_e( 'Disable extra compatibilty logic?', 'autoptimize' ); ?></th> <td><label class="cb_label"><input type="checkbox" name="autoptimize_installed_before_compatibility" <?php echo $conf->get( 'autoptimize_installed_before_compatibility' ) ? 'checked="checked" ' : ''; ?>/> <?php esc_html_e( 'Autoptimize applies extra "compatibiity logic" to prevent issues with JS optimization (for e.g. Gutenberg blocks, Revolution Slider, jQuery-heavy plugins, ...) but may sometimes be a bit too careful. If you have render-blocking JS issues, you can try disabling this logic here. Make sure to test your site thoroughly though!', 'autoptimize' ); ?></label></td> </tr> </table> </li> </ul> <p class="submit"> <input type="submit" class="button-secondary" value="<?php esc_html_e( 'Save Changes', 'autoptimize' ); ?>" /> <input type="submit" class="button-primary" name="autoptimize_cache_clean" value="<?php esc_html_e( 'Save Changes and Empty Cache', 'autoptimize' ); ?>" /> </p> </form> </div> <div id="autoptimize_admin_feed"> <?php if ( apply_filters( 'autoptimize_filter_show_partner_tabs', true ) ) { ?> <div class="autoptimize_banner hidden"> <ul> <?php if ( $this->settings_screen_do_remote_http ) { $ao_banner = get_transient( 'autoptimize_banner' ); if ( empty( $ao_banner ) ) { $banner_resp = wp_remote_get( 'https://misc.optimizingmatters.com/autoptimize_news.html?ao_ver=' . AUTOPTIMIZE_PLUGIN_VERSION ); if ( ! is_wp_error( $banner_resp ) ) { if ( '200' == wp_remote_retrieve_response_code( $banner_resp ) ) { $ao_banner = wp_kses_post( wp_remote_retrieve_body( $banner_resp ) ); set_transient( 'autoptimize_banner', $ao_banner, WEEK_IN_SECONDS ); } } } echo $ao_banner; } ?> <li> <?php // translators: link to the AO FAQ. printf( esc_html__( 'Need help? %1$sCheck out the FAQ here%2$s.', 'autoptimize' ), '<a href=\'https://wordpress.org/plugins/autoptimize/faq/\'>', '</a>' ); ?> </li> <li><?php esc_html_e( 'Happy with Autoptimize?', 'autoptimize' ); ?><br /><a href="<?php echo network_admin_url(); ?>plugin-install.php?tab=search&type=author&s=optimizingmatters"><?php esc_html_e( 'Try my other plugins!', 'autoptimize' ); ?></a></li> </ul> </div> <?php } ?> <div style="margin-left:10px;margin-top:-5px;"> <h2> <?php esc_html_e( 'Autoptimize news', 'autoptimize' ); ?> </h2> <div id="futtta_feed"> <div id="autoptimizefeed"> <?php $this->get_futtta_feeds( 'http://feeds.feedburner.com/futtta_autoptimize' ); ?> </div> </div> </div> <?php if ( apply_filters( 'autoptimize_filter_show_partner_tabs', true ) ) { ?> <div style="float:right;margin:50px 15px;"><a href="https://blog.futtta.be/2013/10/21/do-not-donate-to-me/" target="_blank"><img width="100px" height="85px" src="<?php echo plugins_url() . '/' . plugin_basename( dirname( __FILE__ ) ) . '/external/do_not_donate_smallest.png'; ?>" title="<?php esc_html_e( 'Do not donate for this plugin!', 'autoptimize' ); ?>"></a></div> <?php } ?> </div> <script type="text/javascript"> jQuery(document).ready(function() { check_ini_state(); jQuery('.autoptimize_banner').unslider({autoplay:true, delay:3500, infinite: false, arrows:{prev:'<a class="unslider-arrow prev"></a>', next:'<a class="unslider-arrow next"></a>'}}).fadeTo("slow",1).show(); jQuery( "#autoptimize_html" ).change(function() { if (this.checked) { jQuery(".html_sub:visible").fadeTo("fast",1); } else { jQuery(".html_sub:visible").fadeTo("fast",.33); } }); jQuery( "#autoptimize_js" ).change(function() { if (this.checked) { jQuery(".js_sub:visible").fadeTo("fast",1); } else { jQuery(".js_sub:visible").fadeTo("fast",.33); } }); jQuery( "#autoptimize_js_aggregate" ).change(function() { if (this.checked && jQuery("#autoptimize_js").prop('checked')) { jQuery( "#autoptimize_js_defer_not_aggregate" ).prop( 'checked', false ); // uncheck "defer not aggregate" jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // ungrey self jQuery( ".js_aggregate" ).show( 'slow' ); // show sub-items jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', .33 ); // grey out "not aggregate" jQuery( ".js_not_aggregate" ).hide( 'slow' ); // hide not aggregate sub-items jQuery( "#min_excl_row" ).show(); // make sure "minify excluded" is visible check_exclusions( "js", "on" ); } else { jQuery( ".js_aggregate" ).hide( 'slow' ); // hide sub-itmes jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // un-grey-out "not aggregate" if ( jQuery( "#autoptimize_css_aggregate" ).prop( 'checked' ) == false ) { // hide "minify excluded" jQuery( "#min_excl_row" ).hide(); } check_exclusions( "js", "off" ); } }); jQuery( "#autoptimize_js_defer_not_aggregate" ).change(function() { if (this.checked && jQuery("#autoptimize_js").prop('checked')) { jQuery( "#autoptimize_js_aggregate" ).prop( 'checked', false ); // uncheck "aggregate JS" jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // ungrey self jQuery( ".js_not_aggregate" ).show( 'slow'); // show sub-items jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', .33 ); // grey out "aggregate" jQuery( ".js_aggregate" ).hide( 'slow' ); // hide aggregate sub-items check_exclusions( "js", "off" ); } else { jQuery( ".js_not_aggregate" ).hide( 'slow' ); // hide sub-items jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // un-grey-out "aggregate" } }); jQuery( "#autoptimize_css" ).change(function() { if (this.checked) { jQuery(".css_sub:visible").fadeTo("fast",1); } else { jQuery(".css_sub:visible").fadeTo("fast",.33); } }); jQuery( "#autoptimize_css_aggregate" ).change(function() { if (this.checked && jQuery("#autoptimize_css").prop('checked')) { jQuery(".css_aggregate:visible").fadeTo("fast",1); jQuery( "#min_excl_row" ).show(); check_exclusions( "css", "on" ); } else { jQuery(".css_aggregate:visible").fadeTo("fast",.33); if ( jQuery( "#autoptimize_js_aggregate" ).prop('checked') == false ) { jQuery( "#min_excl_row" ).hide(); } check_exclusions( "css", "off" ); } }); jQuery( "#autoptimize_css_inline" ).change(function() { if (this.checked) { jQuery("#autoptimize_css_defer").prop("checked",false); jQuery("#autoptimize_css_defer_inline").hide("slow"); } }); jQuery( "#autoptimize_css_defer" ).change(function() { if (this.checked) { jQuery("#autoptimize_css_inline").prop("checked",false); jQuery("#autoptimize_css_defer_inline").show("slow"); } else { jQuery("#autoptimize_css_defer_inline").hide("slow"); } }); jQuery( "#autoptimize_enable_site_config" ).change(function() { if (this.checked) { jQuery("li.itemDetail:not(.multiSite)").fadeTo("fast",.33); } else { jQuery("li.itemDetail:not(.multiSite)").fadeTo("fast",1); } }); }) // validate cdn_url. var cdn_url=document.getElementById("cdn_url"); cdn_url_baseCSS=cdn_url.style.cssText; if ("validity" in cdn_url) { jQuery("#cdn_url").focusout(function (event) { if (cdn_url.validity.valid) { cdn_url.style.cssText=cdn_url_baseCSS; } else { cdn_url.style.cssText=cdn_url_baseCSS+"border:1px solid #f00;color:#f00;box-shadow: 0 0 2px #f00;"; }}); } function check_ini_state() { if (!jQuery("#autoptimize_css_defer").prop('checked')) { jQuery("#autoptimize_css_defer_inline").hide(); } if (!jQuery("#autoptimize_html").prop('checked')) { jQuery(".html_sub:visible").fadeTo('fast',.33); } if (!jQuery("#autoptimize_css").prop('checked')) { jQuery(".css_sub:visible").fadeTo('fast',.33); } if (!jQuery("#autoptimize_css_aggregate").prop('checked')) { jQuery(".css_aggregate:visible").fadeTo('fast',.33); } if (jQuery("#autoptimize_js_aggregate").prop('checked')) { jQuery( ".js_aggregate" ).show( 'fast' ); jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'fast', .33 ); } if (jQuery("#autoptimize_js_defer_not_aggregate").prop('checked')) { jQuery( ".js_not_aggregate" ).show( 'fast' ); jQuery( ".js_aggregate_master:visible" ).fadeTo( 'fast', .33 ); } if (jQuery("#autoptimize_enable_site_config").prop('checked')) { jQuery("li.itemDetail:not(.multiSite)").fadeTo('fast',.33); } if (!jQuery("#autoptimize_js").prop('checked')) { jQuery(".js_sub:visible").fadeTo('fast',.33); } } function check_exclusions( what, state ) { exclusion_node = 'input[name="autoptimize_' + what + '_exclude"]'; current_exclusion = jQuery( exclusion_node ).val(); if ( what == "js" ) { default_exclusion = ", wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.min.js"; } else if ( what == "css") { default_exclusion = ", admin-bar.min.css, dashicons.min.css, wp-content/cache/, wp-content/uploads/"; } default_in_current = current_exclusion.indexOf(default_exclusion); if ( state == "on" && default_in_current == -1 ) { jQuery( exclusion_node ).val( current_exclusion + default_exclusion ); } else if ( state = "off" && current_exclusion == default_exclusion ) { jQuery( exclusion_node ).val( "" ); } else if ( state = "off" && default_in_current != -1 ) { new_exclusion = current_exclusion.substring( 0, default_in_current) + current_exclusion.substring( default_in_current + default_exclusion.length, current_exclusion.length ); jQuery( exclusion_node ).val( new_exclusion ); } } </script> </div> <?php } public function addmenu() { $_my_name = apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html__( 'Autoptimize Pro', 'autoptimize' ) : esc_html__( 'Autoptimize', 'autoptimize' ); global $title; if ( empty( $title ) && true === autoptimizeUtils::is_ao_settings() ) { $title = $_my_name; } if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) { // multisite, network admin, ao network activated: add normal settings page at network level. $hook = add_submenu_page( 'settings.php', esc_html__( 'Autoptimize Options', 'autoptimize' ), $_my_name, 'manage_network_options', 'autoptimize', array( $this, 'show_config' ) ); } elseif ( is_multisite() && ! is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_enable_site_config' ) ) { // multisite, ao network activated, not network admin so site specific settings, but "autoptimize_enable_site_config" is off: show "sorry, ask network admin" message iso options. $hook = add_options_page( esc_html__( 'Autoptimize Options', 'autoptimize' ), $_my_name, 'manage_options', 'autoptimize', array( $this, 'show_network_message' ) ); } else { // default: show normal options page if not multisite, if multisite but not network activated, if multisite and network activated and "autoptimize_enable_site_config" is on. $hook = add_options_page( esc_html__( 'Autoptimize Options', 'autoptimize' ), $_my_name, 'manage_options', 'autoptimize', array( $this, 'show_config' ) ); } add_action( 'admin_print_scripts-' . $hook, array( $this, 'autoptimize_admin_scripts' ) ); add_action( 'admin_print_styles-' . $hook, array( $this, 'autoptimize_admin_styles' ) ); } public function autoptimize_admin_scripts() { wp_enqueue_script( 'unslider', plugins_url( '/external/js/unslider.min.js', __FILE__ ), array( 'jquery' ), AUTOPTIMIZE_PLUGIN_VERSION, true ); } public function autoptimize_admin_styles() { wp_enqueue_style( 'unslider', plugins_url( '/external/js/unslider.css', __FILE__ ), null, AUTOPTIMIZE_PLUGIN_VERSION ); wp_enqueue_style( 'unslider-dots', plugins_url( '/external/js/unslider-dots.css', __FILE__ ), null, AUTOPTIMIZE_PLUGIN_VERSION ); } public function registersettings() { register_setting( 'autoptimize', 'autoptimize_html' ); register_setting( 'autoptimize', 'autoptimize_html_keepcomments' ); register_setting( 'autoptimize', 'autoptimize_html_minify_inline' ); register_setting( 'autoptimize', 'autoptimize_enable_site_config' ); register_setting( 'autoptimize', 'autoptimize_js' ); register_setting( 'autoptimize', 'autoptimize_js_aggregate' ); register_setting( 'autoptimize', 'autoptimize_js_defer_not_aggregate' ); register_setting( 'autoptimize', 'autoptimize_js_defer_inline' ); register_setting( 'autoptimize', 'autoptimize_js_exclude' ); register_setting( 'autoptimize', 'autoptimize_js_trycatch' ); register_setting( 'autoptimize', 'autoptimize_js_justhead' ); register_setting( 'autoptimize', 'autoptimize_js_forcehead' ); register_setting( 'autoptimize', 'autoptimize_js_include_inline' ); register_setting( 'autoptimize', 'autoptimize_css' ); register_setting( 'autoptimize', 'autoptimize_css_aggregate' ); register_setting( 'autoptimize', 'autoptimize_css_exclude' ); register_setting( 'autoptimize', 'autoptimize_css_justhead' ); register_setting( 'autoptimize', 'autoptimize_css_datauris' ); register_setting( 'autoptimize', 'autoptimize_css_defer' ); register_setting( 'autoptimize', 'autoptimize_css_defer_inline' ); register_setting( 'autoptimize', 'autoptimize_css_inline' ); register_setting( 'autoptimize', 'autoptimize_css_include_inline' ); register_setting( 'autoptimize', 'autoptimize_cdn_url' ); register_setting( 'autoptimize', 'autoptimize_cache_clean' ); register_setting( 'autoptimize', 'autoptimize_cache_nogzip' ); register_setting( 'autoptimize', 'autoptimize_optimize_logged' ); register_setting( 'autoptimize', 'autoptimize_optimize_checkout' ); register_setting( 'autoptimize', 'autoptimize_minify_excluded' ); register_setting( 'autoptimize', 'autoptimize_cache_fallback' ); register_setting( 'autoptimize', 'autoptimize_enable_meta_ao_settings' ); register_setting( 'autoptimize', 'autoptimize_installed_before_compatibility' ); } public function setmeta( $links, $file = null ) { // Inspired on http://wpengineer.com/meta-links-for-wordpress-plugins/. // Do it only once - saves time. static $plugin; if ( empty( $plugin ) ) { $plugin = plugin_basename( AUTOPTIMIZE_PLUGIN_DIR . 'autoptimize.php' ); } if ( null === $file ) { // 2.7 and lower. $settings_link = sprintf( '<a href="options-general.php?page=autoptimize">%s</a>', esc_html__( 'Settings' ) ); array_unshift( $links, $settings_link ); } else { // 2.8 and higher. // If it's us, add the link. if ( $file === $plugin ) { $newlink = array( sprintf( '<a href="options-general.php?page=autoptimize">%s</a>', esc_html__( 'Settings' ) ) ); $links = array_merge( $links, $newlink ); } } return $links; } /** * Provides the default options. * * @return array */ public static function get_defaults() { static $config = array( 'autoptimize_html' => 1, 'autoptimize_html_keepcomments' => 0, 'autoptimize_html_minify_inline' => 0, 'autoptimize_enable_site_config' => 1, 'autoptimize_js' => 1, 'autoptimize_js_aggregate' => 0, 'autoptimize_js_defer_not_aggregate' => 1, 'autoptimize_js_defer_inline' => 1, 'autoptimize_js_exclude' => '', 'autoptimize_js_trycatch' => 0, 'autoptimize_js_justhead' => 0, 'autoptimize_js_include_inline' => 0, 'autoptimize_js_forcehead' => 0, 'autoptimize_css' => 1, 'autoptimize_css_aggregate' => 0, 'autoptimize_css_exclude' => '', 'autoptimize_css_justhead' => 0, 'autoptimize_css_include_inline' => 0, 'autoptimize_css_defer' => 0, 'autoptimize_css_defer_inline' => '', 'autoptimize_css_inline' => 0, 'autoptimize_css_datauris' => 0, 'autoptimize_cdn_url' => '', 'autoptimize_cache_nogzip' => 1, 'autoptimize_optimize_logged' => 1, 'autoptimize_optimize_checkout' => 0, 'autoptimize_minify_excluded' => 1, 'autoptimize_cache_fallback' => 1, 'autoptimize_enable_meta_ao_settings' => 1, 'autoptimize_installed_before_compatibility' => 0, ); return $config; } /** * Returns default option values for autoptimizeExtra. * * @return array */ public static function get_ao_extra_default_options() { $defaults = array( 'autoptimize_extra_checkbox_field_1' => '0', 'autoptimize_extra_checkbox_field_0' => '0', 'autoptimize_extra_radio_field_4' => '1', 'autoptimize_extra_text_field_2' => '', 'autoptimize_extra_text_field_3' => '', 'autoptimize_extra_text_field_7' => '', 'autoptimize_extra_checkbox_field_8' => '0', ); return $defaults; } /** * Returns default option values for autoptimizeExtra. * * @return array */ public static function get_ao_imgopt_default_options() { $defaults = array( 'autoptimize_imgopt_checkbox_field_1' => '0', // imgopt off. 'autoptimize_imgopt_select_field_2' => '2', // quality glossy. 'autoptimize_imgopt_checkbox_field_3' => '0', // lazy load off. 'autoptimize_imgopt_checkbox_field_4' => '0', // webp off (might be removed). 'autoptimize_imgopt_text_field_5' => '', // lazy load exclusions empty. 'autoptimize_imgopt_text_field_6' => '', // optimization exclusions empty. 'autoptimize_imgopt_number_field_7' => '2', // lazy load from nth image (0 = lazyload all). ); return $defaults; } /** * Returns preload JS onload handler. * * @param string $media media attribute value the JS to use. * * @return string */ public static function get_ao_css_preload_onload( $media = 'all' ) { $preload_onload = apply_filters( 'autoptimize_filter_css_preload_onload', "this.onload=null;this.media='" . $media . "';" ); return $preload_onload; } public function get( $key ) { if ( ! is_array( $this->config ) ) { // Default config. $config = self::get_defaults(); // Override with user settings. foreach ( array_keys( $config ) as $name ) { $conf = autoptimizeOptionWrapper::get_option( $name ); if ( false !== $conf ) { // It was set before! $config[ $name ] = $conf; } } // Save for next call. $this->config = apply_filters( 'autoptimize_filter_get_config', $config ); } if ( isset( $this->config[ $key ] ) ) { return $this->config[ $key ]; } return false; } private function get_futtta_feeds( $url ) { if ( $this->settings_screen_do_remote_http ) { $rss = fetch_feed( $url ); $maxitems = 0; if ( ! is_wp_error( $rss ) ) { $maxitems = $rss->get_item_quantity( 7 ); $rss_items = $rss->get_items( 0, $maxitems ); } ?> <ul> <?php if ( 0 == $maxitems ) : ?> <li><?php esc_html_e( 'No items', 'autoptimize' ); ?></li> <?php else : ?> <?php foreach ( $rss_items as $item ) : ?> <li> <a href="<?php echo esc_url( $item->get_permalink() ); ?>" <?php // translators: the variable contains a date. ?> title="<?php printf( esc_html__( 'Posted %s', 'autoptimize' ), $item->get_date( 'j F Y | g:i a' ) ); ?>"> <?php echo esc_html( $item->get_title() ); ?> </a> </li> <?php endforeach; ?> <?php endif; ?> </ul> <?php } } static function ao_admin_tabs() { // based on http://wordpress.stackexchange.com/a/58826 . $tabs = apply_filters( 'autoptimize_filter_settingsscreen_tabs', array( 'autoptimize' => esc_html__( 'JS, CSS & HTML', 'autoptimize' ) ) ); $tab_content = ''; $tabs_count = count( $tabs ); if ( $tabs_count > 1 ) { if ( isset( $_GET['page'] ) ) { $current_id = $_GET['page']; } else { $current_id = 'autoptimize'; } $tab_content .= '<h2 class="nav-tab-wrapper">'; foreach ( $tabs as $tab_id => $tab_name ) { if ( $current_id == $tab_id ) { $class = ' nav-tab-active'; } else { $class = ''; } $tab_content .= '<a class="nav-tab' . $class . '" href="?page=' . $tab_id . '">' . $tab_name . '</a>'; } $tab_content .= '</h2>'; } else { $tab_content = '<hr/>'; } return $tab_content; } /** * Returns true if in admin (and not in admin-ajax.php!) * * @return bool */ public static function is_admin_and_not_ajax() { return ( is_admin() && ! self::doing_ajax() ); } /** * Returns true if doing ajax. * * @return bool */ protected static function doing_ajax() { if ( function_exists( 'wp_doing_ajax' ) ) { return wp_doing_ajax(); } return ( defined( 'DOING_AJAX' ) && DOING_AJAX ); } /** * Returns true menu or tab is to be shown. * * @return bool */ public static function should_show_menu_tabs() { if ( ! is_multisite() || is_network_admin() || 'on' === autoptimizeOptionWrapper::get_option( 'autoptimize_enable_site_config' ) || false === autoptimizeOptionWrapper::is_ao_active_for_network() ) { return true; } else { return false; } } /** * Returns the post meta AO settings for reuse in different optimizers. * * @param string $optim What optimization we need meta setting for. * * @return bool */ public static function get_post_meta_ao_settings( $optim ) { if ( ! autoptimizeConfig::is_ao_meta_settings_active() ) { // Per page/post settings not active, so always return true (as in; can be optimized). if ( in_array( $optim, apply_filters( 'autoptimize_filter_meta_inactive_return_false_for', array( 'ao_post_preload' ) ) ) ) { // but make sure to return false for text input. return false; } return true; } static $_meta_value = null; if ( null === $_meta_value ) { global $wp_query; if ( isset( $wp_query ) ) { $_meta_value = get_post_meta( get_the_ID(), 'ao_post_optimize', true ); } else { $_meta_value = false; } } // If autoptimize_post_optimize !== 'on' (except for ao_post_preload, which can have other values) then always return false as all is off. // fixme: need unit tests to ensure below logic is sane! if ( empty( $_meta_value ) || ! is_array( $_meta_value ) ) { // no metabox values so all optimizations are a go. if ( in_array( $optim, apply_filters( 'autoptimize_filter_meta_optim_nonbool', array( 'ao_post_preload' ) ) ) ) { // but make sure to return false for text input. return false; } return true; } else if ( array_key_exists( 'ao_post_optimize', $_meta_value ) && 'on' !== $_meta_value['ao_post_optimize'] ) { // ao entirely off for this page. return false; } else if ( in_array( $optim, apply_filters( 'autoptimize_filter_meta_optim_with_filters', array() ) ) ) { // if an $optim is registered as having a filter, apply filter and return that (default false). return apply_filters( 'autoptimize_filter_meta_filtered_optim', false, $optim, $_meta_value ); } else if ( array_key_exists( $optim, $_meta_value ) && empty( $_meta_value[ $optim ] ) ) { // sub-optimization off for this page. return false; } else if ( array_key_exists( $optim, $_meta_value ) && 'on' === $_meta_value[ $optim ] ) { // sub-optimization is explictly on. return true; } else if ( array_key_exists( $optim, $_meta_value ) && in_array( $optim, array( 'ao_post_preload' ) ) && ! empty( $_meta_value[ $optim ] ) ) { // a non-bool metabox optimization (currently only preload field), return value instead of bool. return $_meta_value[ $optim ]; } else if ( in_array( $optim, array( 'ao_post_preload' ) ) && ( ! array_key_exists( $optim, $_meta_value ) || empty( $_meta_value[ $optim ] ) ) ) { // a non-bool metabox optimization not found or empty, so returning false. return false; } else { // when in doubt "go" for optimization, but this should never happen? if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( 'AO metabox logic fallback; well, how did I get here? Maybe this helps: looking for ' . $optim . ' in ' . json_encode( $_meta_value ) ); } return true; } } /** * Are the post meta AO settings active (default: no)? * * @return bool */ public static function is_ao_meta_settings_active() { static $_meta_settings_active = null; if ( null === $_meta_settings_active ) { $_meta_settings_active = apply_filters( 'autoptimize_filter_enable_meta_ao_settings', autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '1' ) ); } return $_meta_settings_active; } } PK ��3\.���X �X classes/autoptimizeUtils.phpnu �[��� <?php /** * General helpers. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeUtils { /** * Returns true when mbstring is available. * * @param bool|null $override Allows overriding the decision. * * @return bool */ public static function mbstring_available( $override = null ) { static $available = null; if ( null === $available ) { $available = \extension_loaded( 'mbstring' ); } if ( null !== $override ) { $available = $override; } return $available; } /** * Multibyte-capable strpos() if support is available on the server. * If not, it falls back to using \strpos(). * * @param string $haystack Haystack. * @param string $needle Needle. * @param int $offset Offset. * @param string|null $encoding Encoding. Default null. * * @return int|false */ public static function strpos( $haystack, $needle, $offset = 0, $encoding = null ) { if ( self::mbstring_available() ) { return ( null === $encoding ) ? \mb_strpos( $haystack, $needle, $offset ) : \mb_strpos( $haystack, $needle, $offset, $encoding ); } else { return \strpos( $haystack, $needle, $offset ); } } /** * Attempts to return the number of characters in the given $string if * mbstring is available. Returns the number of bytes * (instead of characters) as fallback. * * @param string $string String. * @param string|null $encoding Encoding. * * @return int Number of characters or bytes in given $string * (characters if/when supported, bytes otherwise). */ public static function strlen( $string, $encoding = null ) { if ( self::mbstring_available() ) { return ( null === $encoding ) ? \mb_strlen( $string ) : \mb_strlen( $string, $encoding ); } else { return \strlen( $string ); } } /** * Our wrapper around implementations of \substr_replace() * that attempts to not break things horribly if at all possible. * Uses mbstring if available, before falling back to regular * substr_replace() (which works just fine in the majority of cases). * * @param string $string String. * @param string $replacement Replacement. * @param int $start Start offset. * @param int|null $length Length. * @param string|null $encoding Encoding. * * @return string */ public static function substr_replace( $string, $replacement, $start, $length = null, $encoding = null ) { if ( self::mbstring_available() ) { $strlen = self::strlen( $string, $encoding ); if ( $start < 0 ) { if ( -$start < $strlen ) { $start = $strlen + $start; } else { $start = 0; } } elseif ( $start > $strlen ) { $start = $strlen; } if ( null === $length || '' === $length ) { $start2 = $strlen; } elseif ( $length < 0 ) { $start2 = $strlen + $length; if ( $start2 < $start ) { $start2 = $start; } } else { $start2 = $start + $length; } if ( null === $encoding ) { $leader = $start ? \mb_substr( $string, 0, $start ) : ''; $trailer = ( $start2 < $strlen ) ? \mb_substr( $string, $start2, null ) : ''; } else { $leader = $start ? \mb_substr( $string, 0, $start, $encoding ) : ''; $trailer = ( $start2 < $strlen ) ? \mb_substr( $string, $start2, null, $encoding ) : ''; } return "{$leader}{$replacement}{$trailer}"; } return ( null === $length ) ? \substr_replace( $string, $replacement, $start ) : \substr_replace( $string, $replacement, $start, $length ); } /** * Decides whether this is a "subdirectory site" or not. * * @param bool $override Allows overriding the decision when needed. * * @return bool */ public static function siteurl_not_root( $override = null ) { static $subdir = null; if ( null === $subdir ) { $parts = self::get_ao_wp_site_url_parts(); $subdir = ( isset( $parts['path'] ) && ( '/' !== $parts['path'] ) ); } if ( null !== $override ) { $subdir = $override; } return $subdir; } /** * Parse AUTOPTIMIZE_WP_SITE_URL into components using \parse_url(), but do * so only once per request/lifecycle. * * @return array */ public static function get_ao_wp_site_url_parts() { static $parts = array(); if ( empty( $parts ) ) { $parts = \parse_url( AUTOPTIMIZE_WP_SITE_URL ); } return $parts; } /** * Modify given $cdn_url to include the site path when needed. * * @param string $cdn_url CDN URL to tweak. * @param bool $force_cache_miss Force a cache miss in order to be able * to re-run the filter. * * @return string */ public static function tweak_cdn_url_if_needed( $cdn_url, $force_cache_miss = false ) { static $results = array(); if ( ! isset( $results[ $cdn_url ] ) || $force_cache_miss ) { // In order to return unmodified input when there's no need to tweak. $results[ $cdn_url ] = $cdn_url; // Behind a default true filter for backcompat, and only for sites // in a subfolder/subdirectory, but still easily turned off if // not wanted/needed... if ( autoptimizeUtils::siteurl_not_root() ) { $check = apply_filters( 'autoptimize_filter_cdn_magic_path_check', true, $cdn_url ); if ( $check ) { $site_url_parts = autoptimizeUtils::get_ao_wp_site_url_parts(); $cdn_url_parts = \parse_url( $cdn_url ); $schemeless = self::is_protocol_relative( $cdn_url ); $cdn_url_parts = self::maybe_replace_cdn_path( $site_url_parts, $cdn_url_parts ); if ( false !== $cdn_url_parts ) { $results[ $cdn_url ] = self::assemble_parsed_url( $cdn_url_parts, $schemeless ); } } } } return $results[ $cdn_url ]; } /** * When siteurl contains a path other than '/' and the CDN URL does not have * a path or it's path is '/', this will modify the CDN URL's path component * to match that of the siteurl. * This is to support "magic" CDN urls that worked that way before v2.4... * * @param array $site_url_parts Site URL components array. * @param array $cdn_url_parts CDN URL components array. * * @return array|false */ public static function maybe_replace_cdn_path( array $site_url_parts, array $cdn_url_parts ) { if ( isset( $site_url_parts['path'] ) && '/' !== $site_url_parts['path'] ) { if ( ! isset( $cdn_url_parts['path'] ) || '/' === $cdn_url_parts['path'] ) { $cdn_url_parts['path'] = $site_url_parts['path']; return $cdn_url_parts; } } return false; } /** * Given an array or components returned from \parse_url(), assembles back * the complete URL. * If optional * * @param array $parsed_url URL components array. * @param bool $schemeless Whether the assembled URL should be * protocol-relative (schemeless) or not. * * @return string */ public static function assemble_parsed_url( array $parsed_url, $schemeless = false ) { $scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : ''; if ( $schemeless ) { $scheme = '//'; } $host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : ''; $port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : ''; $user = isset( $parsed_url['user'] ) ? $parsed_url['user'] : ''; $pass = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : ''; $pass = ( $user || $pass ) ? "$pass@" : ''; $path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : ''; $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : ''; $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : ''; return "$scheme$user$pass$host$port$path$query$fragment"; } /** * Returns true if given $url is protocol-relative. * * @param string $url URL to check. * * @return bool */ public static function is_protocol_relative( $url ) { $result = false; if ( ! empty( $url ) ) { $result = ( 0 === strpos( $url, '//' ) ); } return $result; } /** * Canonicalizes the given path regardless of it existing or not. * * @param string $path Path to normalize. * * @return string */ public static function path_canonicalize( $path ) { $patterns = array( '~/{2,}~', '~/(\./)+~', '~([^/\.]+/(?R)*\.{2,}/)~', '~\.\./~', ); $replacements = array( '/', '/', '', '', ); return preg_replace( $patterns, $replacements, $path ); } /** * Checks to see if 3rd party services are available and stores result in option * * TODO This should be two separate methods. * * @param string $return_result should we return resulting service status array (default no). * * @return null|array Service status or null. */ public static function check_service_availability( $return_result = false ) { $service_availability_resp = wp_remote_get( 'https://misc.optimizingmatters.com/api/autoptimize_service_availablity.json?from=aomain&ver=' . AUTOPTIMIZE_PLUGIN_VERSION ); if ( ! is_wp_error( $service_availability_resp ) ) { if ( '200' == wp_remote_retrieve_response_code( $service_availability_resp ) ) { $availabilities = json_decode( wp_remote_retrieve_body( $service_availability_resp ), true ); if ( is_array( $availabilities ) ) { autoptimizeOptionWrapper::update_option( 'autoptimize_service_availablity', $availabilities ); if ( $return_result ) { return $availabilities; } } } } return null; } /** * Returns true if the string is a valid regex. * * @param string $string String, duh. * * @return bool */ public static function str_is_valid_regex( $string ) { set_error_handler( function() {}, E_WARNING ); $is_regex = ( false !== preg_match( $string, '' ) ); restore_error_handler(); return $is_regex; } /** * Returns true if a certain WP plugin is active/loaded. * * @param string $plugin_file Main plugin file. * * @return bool */ public static function is_plugin_active( $plugin_file ) { static $ipa_exists = null; if ( null === $ipa_exists ) { if ( ! function_exists( '\is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $ipa_exists = function_exists( '\is_plugin_active' ); } return $ipa_exists && \is_plugin_active( $plugin_file ); } /** * Returns a node without ID attrib for use in noscript tags * * @param string $node an html tag. * * @return string */ public static function remove_id_from_node( $node ) { if ( strpos( $node, 'id=' ) === false || apply_filters( 'autoptimize_filter_utils_keep_ids', false ) ) { return $node; } else { return preg_replace( '#(.*) id=[\'|"].*[\'|"] (.*)#Um', '$1 $2', $node ); } } /** * Returns true if given $str ends with given $test. * * @param string $str String to check. * @param string $test Ending to match. * * @return bool */ public static function str_ends_in( $str, $test ) { // @codingStandardsIgnoreStart // substr_compare() is bugged on 5.5.11: https://3v4l.org/qGYBH // return ( 0 === substr_compare( $str, $test, -strlen( $test ) ) ); // @codingStandardsIgnoreEnd $length = strlen( $test ); return ( substr( $str, -$length, $length ) === $test ); } /** * Returns true if a pagecache is found, false if not. * Now used to show notice, might be used later on to (un)hide page caching in AO if no page cache found. * * @param bool $disregard_transient False by default, but can be used to ignore the transient and retest. * * @return bool */ public static function find_pagecache( $disregard_transient = false ) { static $_found_pagecache = null; if ( null === $_found_pagecache ) { $_page_cache_constants = array( 'NgInx' => 'NGINX_HELPER_BASENAME', 'Kinsta' => 'KINSTAMU_VERSION', 'Presslabs' => 'PL_INSTANCE_REF', 'Cache Enabler' => 'CACHE_ENABLER_VERSION', 'Speed Booster Pack' => 'SBP_PLUGIN_NAME', 'Servebolt' => 'SERVEBOLT_PLUGIN_FILE', 'WP CloudFlare Super Page Cache' => 'SWCFPC_PLUGIN_PATH', 'Cachify' => 'CACHIFY_CACHE_DIR', 'WP Rocket' => 'WP_ROCKET_CACHE_PATH', 'WP Optimize' => 'WPO_VERSION', 'Autoptimize Pro' => 'AO_PRO_PAGECACHE_CACHE_DIR', ); $_page_cache_classes = array( 'Pressidium' => 'Ninukis_Plugin', 'Swift Performance' => 'Swift_Performance_Cache', 'WP Fastest Cache' => 'WpFastestCache', 'Quick Cache' => 'c_ws_plugin__qcache_purging_routines', 'ZenCache' => 'zencache', 'Comet Cache' => 'comet_cache', 'WP Engine' => 'WpeCommon', 'Flywheel' => 'FlywheelNginxCompat', 'Pagely' => 'PagelyCachePurge', ); $_page_cache_functions = array( 'WP Super Cache' => 'wp_cache_clear_cache', 'W3 Total Cache' => 'w3tc_pgcache_flush', 'WP Fast Cache' => 'wp_fast_cache_bulk_delete_all', 'Rapidcache' => 'rapidcache_clear_cache', 'Siteground' => 'sg_cachepress_purge_cache', 'WP Super Cache' => 'prune_super_cache', ); $_found_pagecache = false; if ( true !== $disregard_transient ) { $_ao_pagecache_transient = 'autoptimize_pagecache_check'; $_found_pagecache = get_transient( $_ao_pagecache_transient ); } if ( current_user_can( 'manage_options' ) && false === $_found_pagecache ) { // loop through known pagecache constants. foreach ( $_page_cache_constants as $_name => $_constant ) { if ( defined( $_constant ) ) { $_found_pagecache = $_name; break; } } // and loop through known pagecache classes. if ( false === $_found_pagecache ) { foreach ( $_page_cache_classes as $_name => $_class ) { if ( class_exists( $_class ) ) { $_found_pagecache = $_name; break; } } } // and loop through known pagecache functions. if ( false === $_found_pagecache ) { foreach ( $_page_cache_functions as $_name => $_function ) { if ( function_exists( $_function ) ) { $_found_pagecache = $_name; break; } } } // store in transient for 1 week if pagecache found. if ( true === $_found_pagecache && true !== $disregard_transient ) { set_transient( $_ao_pagecache_transient, true, WEEK_IN_SECONDS ); } } } return $_found_pagecache; } /** * Returns true if on one of the AO settings tabs, false if not. * Used to limit notifications to AO settings pages. * * @return bool */ public static function is_ao_settings() { $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners', 'ao_pro_boosters', 'ao_pro_pagecache', 'ao_protab' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false ); return $_is_ao_settings; } /** * Returns false if no conflicting plugins are found, the name if the plugin if found. * * @return bool|string */ public static function find_potential_conflicts() { if ( defined( 'WPFC_WP_CONTENT_BASENAME' ) ) { $_wpfc_options = json_decode( get_option( 'WpFastestCache' ) ); foreach ( array( 'wpFastestCacheMinifyCss', 'wpFastestCacheCombineCss', 'wpFastestCacheCombineJs' ) as $_wpfc_conflicting ) { if ( isset( $_wpfc_options->$_wpfc_conflicting ) && 'on' === $_wpfc_options->$_wpfc_conflicting ) { return 'WP Fastest Cache'; } } } elseif ( defined( 'W3TC_VERSION' ) ) { $w3tc_config = file_get_contents( WP_CONTENT_DIR . '/w3tc-config/master.php' ); $w3tc_minify_on = strpos( $w3tc_config, '"minify.enabled": true' ); if ( $w3tc_minify_on ) { return 'W3 Total Cache'; } } elseif ( defined( 'SiteGround_Optimizer\VERSION' ) ) { if ( get_option( 'siteground_optimizer_optimize_css' ) == 1 || get_option( 'siteground_optimizer_optimize_javascript' ) == 1 || get_option( 'siteground_optimizer_combine_javascript' ) == 1 || get_option( 'siteground_optimizer_combine_css' ) == 1 ) { return 'Siteground Optimizer'; } } elseif ( defined( 'WPO_VERSION' ) ) { $_wpo_options = get_site_option( 'wpo_minify_config' ); if ( is_array( $_wpo_options ) && 1 == $_wpo_options['enabled'] && ( 1 == $_wpo_options['enable_css'] || 1 == $_wpo_options['enable_js'] ) ) { return 'WP Optimize'; } } elseif ( defined( 'WPACU_PLUGIN_VERSION' ) || defined( 'WPACU_PRO_PLUGIN_VERSION' ) ) { $wpacu_settings_class = new \WpAssetCleanUp\Settings(); $wpacu_settings = $wpacu_settings_class->getAll(); if ( $wpacu_settings['minify_loaded_css'] || $wpacu_settings['minify_loaded_js'] || $wpacu_settings['combine_loaded_js'] || $wpacu_settings['combine_loaded_css'] ) { return 'Asset Cleanup'; } } elseif ( defined( 'WP_ROCKET_VERSION' ) && function_exists( 'get_rocket_option' ) ) { if ( get_rocket_option( 'minify_js' ) || get_rocket_option( 'minify_concatenate_js' ) || get_rocket_option( 'minify_css' ) || get_rocket_option( 'minify_concatenate_css' ) || get_rocket_option( 'async_css' ) ) { return 'WP Rocket'; } } elseif ( function_exists( 'fvm_get_settings' ) ) { return 'Fast Velocity Minify'; } return false; } /** * Returns true if false if on a local dev environment, true if not. * Used to disallow image opt/ critcss for local dev environments. * * @return bool */ public static function is_local_server( $_domain = AUTOPTIMIZE_SITE_DOMAIN ) { static $_is_local_server = null; if ( null === $_is_local_server ) { if ( false === strpos( $_domain, '.' ) && false === strpos( $_domain, ':' ) ) { // no dots in domain or colon (ipv6 address), so impossible to reach, this also matches 'localhost' or any other single-word domain. $_is_local_server = true; } elseif ( in_array( $_domain, array( '127.0.0.1', '0000:0000:0000:0000:0000:0000:0000:0001', '0:0:0:0:0:0:0:1', '::1' ) ) ) { // localhost IPv4/ IPv6. $_is_local_server = true; } elseif ( 0 === strpos( $_domain, '127.' ) || 0 === strpos( $_domain, '192.168.' ) || 0 === strpos( $_domain, '10.' ) || 0 === strpos( $_domain, 'fd' ) ) { // private ranges so unreachable for imgopt/ CCSS. // fixme; 172.16.0.0–172.31.255.255 also private. $_is_local_server = true; } elseif ( autoptimizeUtils::str_ends_in( $_domain, '.local') ) { // matches 'whatever.local'. $_is_local_server = true; } else { // likely OK. $_is_local_server = false; } } // filter to override result for testing purposes. return apply_filters( 'autoptimize_filter_utils_is_local_server', $_is_local_server ); } public static function strip_tags_array( $array ) { // strip all tags in an array (use case: avoid XSS in CCSS rules both when importing and when outputting). // based on https://stackoverflow.com/a/44732196/237449 but heavily tweaked. if ( is_array( $array ) ) { $result = array(); foreach ( $array as $key => $value ){ if ( is_array( $value ) ) { $result[$key] = autoptimizeUtils::strip_tags_array( $value ); } else if ( is_string( $value ) ) { $result[$key] = wp_strip_all_tags( $value ); } else { $result[$key] = $value; } } } else { $result = wp_strip_all_tags( $array ); } return $result; } } PK ��3\�E� � classes/autoptimizeToolbar.phpnu �[��� <?php /** * Handles toolbar-related stuff. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeToolbar { public function __construct() { // If Cache is not available we don't add the toolbar. if ( ! autoptimizeCache::cacheavail() ) { return; } // Load admin toolbar feature once WordPress, all plugins, and the theme are fully loaded and instantiated. if ( is_admin() ) { add_action( 'wp_loaded', array( $this, 'load_toolbar' ) ); } else { // to avoid AMP complaining about the AMP conditional being checked too early. add_action( 'wp', array( $this, 'load_toolbar' ) ); } } public function load_toolbar() { // Check permissions and that toolbar is not hidden via filter. if ( current_user_can( 'manage_options' ) && apply_filters( 'autoptimize_filter_toolbar_show', true ) && ! autoptimizeMain::is_amp_markup( '' ) ) { // Create a handler for the AJAX toolbar requests. add_action( 'wp_ajax_autoptimize_delete_cache', array( $this, 'delete_cache' ) ); // Load custom styles, scripts and menu only when needed. if ( is_admin_bar_showing() ) { if ( is_admin() ) { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); } else { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); } // Add the Autoptimize Toolbar to the Admin bar. add_action( 'admin_bar_menu', array( $this, 'add_toolbar' ), 100 ); } } } public function add_toolbar() { global $wp_admin_bar; // Retrieve the Autoptimize Cache Stats information. $stats = autoptimizeCache::stats(); // Set the Max Size recommended for cache files. $max_size = apply_filters( 'autoptimize_filter_cachecheck_maxsize', 512 * 1024 * 1024 ); // Retrieve the current Total Files in cache. $files = $stats[0]; // Retrieve the current Total Size of the cache. $bytes = $stats[1]; $size = $this->format_filesize( $bytes ); // Calculate the percentage of cache used. $percentage = ceil( $bytes / $max_size * 100 ); if ( $percentage > 100 ) { $percentage = 100; } /** * We define the type of color indicator for the current state of cache size: * - "green" if the size is less than 80% of the total recommended. * - "orange" if over 80%. * - "red" if over 100%. */ $color = ( 100 == $percentage ) ? 'red' : ( ( $percentage > 80 ) ? 'orange' : 'green' ); // Create or add new items into the Admin Toolbar. // Main "Autoptimize" node. $_my_name = apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html__( 'Autoptimize Pro', 'autoptimize' ) : esc_html__( 'Autoptimize', 'autoptimize' ); $wp_admin_bar->add_node( array( 'id' => 'autoptimize', 'title' => '<span class="ab-icon"></span><span class="ab-label">' . $_my_name . '</span>', 'href' => admin_url( 'options-general.php?page=autoptimize' ), 'meta' => array( 'class' => 'bullet-' . $color ), ) ); // "Cache Info" node. $wp_admin_bar->add_node( array( 'id' => 'autoptimize-cache-info', 'title' => '<p>' . esc_html__( 'CSS/ JS Cache Info', 'autoptimize' ) . '</p>' . '<div class="autoptimize-radial-bar" percentage="' . $percentage . '">' . '<div class="autoptimize-circle">' . '<div class="mask full"><div class="fill bg-' . $color . '"></div></div>' . '<div class="mask half"><div class="fill bg-' . $color . '"></div></div>' . '<div class="shadow"></div>' . '</div>' . '<div class="inset"><div class="percentage"><div class="numbers ' . $color . '">' . $percentage . '%</div></div></div>' . '</div>' . '<table>' . '<tr><td>' . esc_html__( 'Size', 'autoptimize' ) . ':</td><td class="size ' . $color . '">' . $size . '</td></tr>' . '<tr><td>' . esc_html__( 'Files', 'autoptimize' ) . ':</td><td class="files white">' . $files . '</td></tr>' . '</table>', 'parent' => 'autoptimize', ) ); // "Delete Cache" node. $wp_admin_bar->add_node( array( 'id' => 'autoptimize-delete-cache', 'title' => esc_html__( 'Clear CSS/ JS Cache', 'autoptimize' ), 'parent' => 'autoptimize', ) ); } public function delete_cache() { check_ajax_referer( 'ao_delcache_nonce', 'nonce' ); $result = false; if ( current_user_can( 'manage_options' ) ) { // We call the function for cleaning the Autoptimize cache. $result = autoptimizeCache::clearall(); } wp_send_json( $result ); } public function enqueue_scripts() { // Autoptimize Toolbar Styles. wp_enqueue_style( 'autoptimize-toolbar', plugins_url( '/static/toolbar.min.css', __FILE__ ), array(), AUTOPTIMIZE_PLUGIN_VERSION, 'all' ); // Autoptimize Toolbar Javascript. wp_enqueue_script( 'autoptimize-toolbar', plugins_url( '/static/toolbar.min.js', __FILE__ ), array( 'jquery' ), AUTOPTIMIZE_PLUGIN_VERSION, true ); // Localizes a registered script with data for a JavaScript variable. // Needed for the AJAX to work properly on the frontend. wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), // translators: links to the Autoptimize settings page. 'error_msg' => sprintf( esc_html__( 'Your Autoptimize cache might not have been purged successfully, please check on the %1$sAutoptimize settings page%2$s.', 'autoptimize' ), '<a href="' . admin_url( 'options-general.php?page=autoptimize' ) . '" style="white-space:nowrap;">', '</a>' ), 'dismiss_msg' => esc_html__( 'Dismiss this notice.' ), 'nonce' => wp_create_nonce( 'ao_delcache_nonce' ), ) ); } public function format_filesize( $bytes, $decimals = 2 ) { $units = array( 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ); for ( $i = 0; ( $bytes / 1024) > 0.9; $i++, $bytes /= 1024 ) {} // @codingStandardsIgnoreLine return sprintf( "%1.{$decimals}f %s", round( $bytes, $decimals ), $units[ $i ] ); } } PK ��3\��mJ� J� classes/autoptimizeMain.phpnu �[��� <?php /** * Wraps base plugin logic/hooks and handles activation/deactivation/uninstall. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class autoptimizeMain { const INIT_EARLIER_PRIORITY = -1; const DEFAULT_HOOK_PRIORITY = 2; /** * Version string. * * @var string */ protected $version = null; /** * Main plugin filepath. * Used for activation/deactivation/uninstall hooks. * * @var string */ protected $filepath = null; /** * Critical CSS base object * * @var object */ protected $_criticalcss = null; /** * Constructor. * * @param string $version Version. * @param string $filepath Filepath. Needed for activation/deactivation/uninstall hooks. */ public function __construct( $version, $filepath ) { $this->version = $version; $this->filepath = $filepath; } public function run() { $this->add_hooks(); // Runs cache size checker. $checker = new autoptimizeCacheChecker(); $checker->run(); } protected function add_hooks() { if ( ! defined( 'AUTOPTIMIZE_SETUP_INITHOOK' ) ) { define( 'AUTOPTIMIZE_SETUP_INITHOOK', 'plugins_loaded' ); } add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'setup' ) ); add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'hook_page_cache_purge' ) ); add_action( 'autoptimize_setup_done', array( $this, 'version_upgrades_check' ) ); add_action( 'autoptimize_setup_done', array( $this, 'check_cache_and_run' ) ); add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_ao_compat' ), 10 ); add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_ao_extra' ), 15 ); add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_admin_only_trinkets' ), 20 ); add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_criticalcss' ), 11 ); add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_notfound_fallback' ), 10 ); add_action( 'init', array( $this, 'load_textdomain' ) ); if ( is_multisite() && is_admin() ) { // Only if multisite and if in admin we want to check if we need to save options on network level. add_action( 'init', 'autoptimizeOptionWrapper::check_multisite_on_saving_options' ); } // register uninstall & deactivation hooks. register_uninstall_hook( $this->filepath, 'autoptimizeMain::on_uninstall' ); register_deactivation_hook( $this->filepath, 'autoptimizeMain::on_deactivation' ); } public function load_textdomain() { load_plugin_textdomain( 'autoptimize' ); } public function setup() { // Do we gzip in php when caching or is the webserver doing it? define( 'AUTOPTIMIZE_CACHE_NOGZIP', (bool) autoptimizeOptionWrapper::get_option( 'autoptimize_cache_nogzip' ) ); // These can be overridden by specifying them in wp-config.php or such. if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_NAME' ) ) { define( 'AUTOPTIMIZE_WP_CONTENT_NAME', '/' . wp_basename( WP_CONTENT_DIR ) ); } if ( ! defined( 'AUTOPTIMIZE_CACHE_CHILD_DIR' ) ) { define( 'AUTOPTIMIZE_CACHE_CHILD_DIR', '/cache/autoptimize/' ); } if ( ! defined( 'AUTOPTIMIZE_CACHEFILE_PREFIX' ) ) { define( 'AUTOPTIMIZE_CACHEFILE_PREFIX', 'autoptimize_' ); } // Note: trailing slash is not optional! if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) { define( 'AUTOPTIMIZE_CACHE_DIR', autoptimizeCache::get_pathname() ); } define( 'WP_ROOT_DIR', substr( WP_CONTENT_DIR, 0, strlen( WP_CONTENT_DIR ) - strlen( AUTOPTIMIZE_WP_CONTENT_NAME ) ) ); if ( ! defined( 'AUTOPTIMIZE_WP_SITE_URL' ) ) { if ( function_exists( 'domain_mapping_siteurl' ) ) { define( 'AUTOPTIMIZE_WP_SITE_URL', domain_mapping_siteurl( get_current_blog_id() ) ); } else { define( 'AUTOPTIMIZE_WP_SITE_URL', site_url() ); } } if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_URL' ) ) { if ( function_exists( 'get_original_url' ) ) { define( 'AUTOPTIMIZE_WP_CONTENT_URL', str_replace( get_original_url( AUTOPTIMIZE_WP_SITE_URL ), AUTOPTIMIZE_WP_SITE_URL, content_url() ) ); } else { define( 'AUTOPTIMIZE_WP_CONTENT_URL', content_url() ); } } if ( ! defined( 'AUTOPTIMIZE_CACHE_URL' ) ) { if ( is_multisite() && apply_filters( 'autoptimize_separate_blog_caches', true ) ) { $blog_id = get_current_blog_id(); define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR . $blog_id . '/' ); } else { define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR ); } } if ( ! defined( 'AUTOPTIMIZE_WP_ROOT_URL' ) ) { define( 'AUTOPTIMIZE_WP_ROOT_URL', str_replace( AUTOPTIMIZE_WP_CONTENT_NAME, '', AUTOPTIMIZE_WP_CONTENT_URL ) ); } if ( ! defined( 'AUTOPTIMIZE_HASH' ) ) { define( 'AUTOPTIMIZE_HASH', wp_hash( AUTOPTIMIZE_CACHE_URL ) ); } if ( ! defined( 'AUTOPTIMIZE_SITE_DOMAIN' ) ) { define( 'AUTOPTIMIZE_SITE_DOMAIN', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ); } // Multibyte-capable string replacements are available with a filter. // Also requires 'mbstring' extension. $with_mbstring = apply_filters( 'autoptimize_filter_main_use_mbstring', false ); if ( $with_mbstring ) { autoptimizeUtils::mbstring_available( \extension_loaded( 'mbstring' ) ); } else { autoptimizeUtils::mbstring_available( false ); } do_action( 'autoptimize_setup_done' ); } /** * Checks if there's a need to upgrade/update options and whatnot, * in which case we might need to do stuff and flush the cache * to avoid old versions of aggregated files lingering around. */ public function version_upgrades_check() { autoptimizeVersionUpdatesHandler::check_installed_and_update( $this->version ); } public function check_cache_and_run() { if ( autoptimizeCache::cacheavail() ) { $conf = autoptimizeConfig::instance(); if ( $conf->get( 'autoptimize_html' ) || $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) || autoptimizeImages::imgopt_active() || autoptimizeImages::should_lazyload_wrapper() ) { if ( ! defined( 'AUTOPTIMIZE_NOBUFFER_OPTIMIZE' ) ) { // Hook into WordPress frontend. if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) { add_action( 'init', array( $this, 'start_buffering' ), self::INIT_EARLIER_PRIORITY ); } else { if ( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) ) { define( 'AUTOPTIMIZE_HOOK_INTO', 'template_redirect' ); } add_action( constant( 'AUTOPTIMIZE_HOOK_INTO' ), array( $this, 'start_buffering' ), self::DEFAULT_HOOK_PRIORITY ); } } // And disable Jetpack's site accelerator if JS or CSS opt. are active. if ( class_exists( 'Jetpack' ) && apply_filters( 'autoptimize_filter_main_disable_jetpack_cdn', true ) && ( $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) || autoptimizeImages::imgopt_active() ) ) { add_filter( 'jetpack_force_disable_site_accelerator', '__return_true' ); // this does not seemt to work any more? if ( true === autoptimizeImages::imgopt_active() ) { // only disable photon if AO is optimizing images. add_filter( 'jetpack_photon_skip_for_url', '__return_true' ); } } // Add "no cache found" notice. add_action( 'admin_notices', 'autoptimizeMain::notice_nopagecache', 99 ); add_action( 'admin_notices', 'autoptimizeMain::notice_potential_conflict', 99 ); } } else { add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' ); } } public function maybe_run_ao_extra() { if ( apply_filters( 'autoptimize_filter_extra_activate', true ) ) { $ao_imgopt = new autoptimizeImages(); $ao_imgopt->run(); $ao_extra = new autoptimizeExtra(); $ao_extra->run(); // And show the imgopt notice. add_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' ); add_action( 'admin_notices', 'autoptimizeMain::notice_imgopt_issue' ); } } public function maybe_run_admin_only_trinkets() { // Loads partners tab and exit survey code if in admin (and not in admin-ajax.php)! if ( autoptimizeConfig::is_admin_and_not_ajax() ) { new autoptimizePartners(); new autoptimizeExitSurvey(); new autoptimizeProTab(); } } public function criticalcss() { if ( apply_filters( 'autoptimize_filter_criticalcss_active', true ) && ! autoptimizeUtils::is_plugin_active( 'autoptimize-criticalcss/ao_criticss_aas.php' ) ) { return $this->_criticalcss; } else { return false; } } public function maybe_run_criticalcss() { // Loads criticalcss if the filter returns true & old power-up is not active. if ( apply_filters( 'autoptimize_filter_criticalcss_active', true ) && ! autoptimizeUtils::is_plugin_active( 'autoptimize-criticalcss/ao_criticss_aas.php' ) ) { $this->_criticalcss = new autoptimizeCriticalCSSBase(); $this->_criticalcss->setup(); $this->_criticalcss->load_requires(); } } public function maybe_run_notfound_fallback() { if ( autoptimizeCache::do_fallback() ) { add_action( 'template_redirect', array( 'autoptimizeCache', 'wordpress_notfound_fallback' ) ); } } public function maybe_run_ao_compat() { $conf = autoptimizeConfig::instance(); // Condtionally loads the compatibility-class to ensure more out-of-the-box compatibility with big players. $_run_compat = true; if ( 'on' === $conf->get( 'autoptimize_installed_before_compatibility' ) ) { // If AO was already running before Compatibility logic was added, don't run compat by default // because it can be assumed everything works and we want to avoid (perf) regressions that // could occur due to compatibility code. $_run_compat = false; } if ( apply_filters( 'autoptimize_filter_init_compatibility', $_run_compat ) ) { new autoptimizeCompatibility(); } } public function hook_page_cache_purge() { // hook into a collection of page cache purge actions if filter allows. if ( apply_filters( 'autoptimize_filter_main_hookpagecachepurge', true ) ) { $page_cache_purge_actions = array( 'after_rocket_clean_domain', // exists. 'hyper_cache_purged', // Stefano confirmed this will be added. 'w3tc_flush_posts', // exits. 'w3tc_flush_all', // exists. 'ce_action_cache_cleared', // Sven confirmed this will be added. 'aoce_action_cache_cleared', // Some other cache enabler. 'comet_cache_wipe_cache', // still to be confirmed by Raam. 'wp_cache_cleared', // cfr. https://github.com/Automattic/wp-super-cache/pull/537. 'wpfc_delete_cache', // Emre confirmed this will be added this. 'swift_performance_after_clear_all_cache', // swift perf. yeah! 'wpo_cache_flush', // wp-optimize. 'rt_nginx_helper_after_fastcgi_purge_all', // nginx helper. ); $page_cache_purge_actions = apply_filters( 'autoptimize_filter_main_pagecachepurgeactions', $page_cache_purge_actions ); foreach ( $page_cache_purge_actions as $purge_action ) { add_action( $purge_action, 'autoptimizeCache::clearall_actionless' ); } } } /** * Setup output buffering if needed. * * @return void */ public function start_buffering() { if ( $this->should_buffer() ) { // Load speedupper conditionally (true by default). if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) { $ao_speedupper = new autoptimizeSpeedupper(); } $conf = autoptimizeConfig::instance(); if ( $conf->get( 'autoptimize_js' ) ) { if ( ! defined( 'CONCATENATE_SCRIPTS' ) ) { define( 'CONCATENATE_SCRIPTS', false ); } if ( ! defined( 'COMPRESS_SCRIPTS' ) ) { define( 'COMPRESS_SCRIPTS', false ); } } if ( $conf->get( 'autoptimize_css' ) ) { if ( ! defined( 'COMPRESS_CSS' ) ) { define( 'COMPRESS_CSS', false ); } } if ( apply_filters( 'autoptimize_filter_obkiller', false ) ) { while ( ob_get_level() > 0 ) { ob_end_clean(); } } // Now, start the real thing! ob_start( array( $this, 'end_buffering' ) ); } } /** * Returns true if all the conditions to start output buffering are satisfied. * * @param bool $doing_tests Allows overriding the optimization of only * deciding once per request (for use in tests). * @return bool */ public static function should_buffer( $doing_tests = false ) { static $do_buffering = null; // Only check once in case we're called multiple times by others but // still allows multiple calls when doing tests. if ( null === $do_buffering || $doing_tests ) { $ao_noptimize = false; // Checking for DONOTMINIFY constant as used by e.g. WooCommerce POS. if ( defined( 'DONOTMINIFY' ) && ( constant( 'DONOTMINIFY' ) === true || constant( 'DONOTMINIFY' ) === 'true' ) ) { $ao_noptimize = true; } // Skip checking query strings if they're disabled. if ( apply_filters( 'autoptimize_filter_honor_qs_noptimize', true ) ) { // Check for `ao_noptimize` (and other) keys in the query string // to get non-optimized page for debugging. $keys = array( 'ao_noptimize', 'ao_noptirocket', ); foreach ( $keys as $key ) { if ( array_key_exists( $key, $_GET ) && '1' === $_GET[ $key ] ) { $ao_noptimize = true; break; } } } // If setting says not to optimize logged in user and user is logged in... if ( false === $ao_noptimize && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_optimize_logged', 'on' ) && is_user_logged_in() && current_user_can( 'edit_posts' ) ) { $ao_noptimize = true; } // If setting says not to optimize cart/checkout. if ( false === $ao_noptimize && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_optimize_checkout', 'off' ) ) { // Checking for woocommerce, easy digital downloads and wp ecommerce... foreach ( array( 'is_checkout', 'is_cart', 'is_account_page', 'edd_is_checkout', 'wpsc_is_cart', 'wpsc_is_checkout' ) as $func ) { if ( function_exists( $func ) && $func() ) { $ao_noptimize = true; break; } } } // Misc. querystring paramaters that will stop AO from doing optimizations (pagebuilders + // 2 generic parameters that could/ should become standard between optimization plugins?). if ( false === $ao_noptimize ) { $_qs_showstoppers = array( 'no_cache', 'no_optimize', 'tve', 'elementor-preview', 'fl_builder', 'vc_action', 'et_fb', 'bt-beaverbuildertheme', 'ct_builder', 'fb-edit', 'siteorigin_panels_live_editor', 'preview', 'td_action' ); // doing Jonathan a quick favor to allow correct unused CSS generation ;-) . if ( apply_filters( 'autoptimize_filter_main_showstoppers_do_wp_rocket_a_favor', true ) ) { $_qs_showstoppers[] = 'nowprocket'; } foreach ( $_qs_showstoppers as $_showstopper ) { if ( array_key_exists( $_showstopper, $_GET ) ) { $ao_noptimize = true; break; } } } // Also honor PageSpeed=off parameter as used by mod_pagespeed, in use by some pagebuilders, // see https://www.modpagespeed.com/doc/experiment#ModPagespeed for info on that. if ( false === $ao_noptimize && array_key_exists( 'PageSpeed', $_GET ) && 'off' === $_GET['PageSpeed'] ) { $ao_noptimize = true; } // If page/ post check post_meta to see if optimize is off. if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_optimize' ) ) { $ao_noptimize = true; } // And finally allows blocking of autoptimization on your own terms regardless of above decisions. $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize ); // Check for site being previewed in the Customizer (available since WP 4.0). $is_customize_preview = false; if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) { $is_customize_preview = is_customize_preview(); } // explicitly disable when is_login exists and is true but don't use it direclty because older versions of WordPress don't have that yet. $is_login = false; if ( function_exists( 'is_login' ) && true === is_login() ) { $is_login = true; } /** * We only buffer the frontend requests (and then only if not a feed * and not turned off explicitly and not when being previewed in Customizer)! * NOTE: Tests throw a notice here due to is_feed() being called * while the main query hasn't been ran yet. Thats why we use * AUTOPTIMIZE_INIT_EARLIER in tests. */ $do_buffering = ( ! is_admin() && ! is_feed() && ! is_embed() && ! $is_login && ! $is_customize_preview && ! $ao_noptimize ); } return $do_buffering; } /** * Returns true if given markup is considered valid/processable/optimizable. * * @param string $content Markup. * * @return bool */ public function is_valid_buffer( $content ) { // Defaults to true. $valid = true; $has_no_html_tag = ( false === stripos( $content, '<html' ) ); $has_xsl_stylesheet = ( false !== stripos( $content, '<xsl:stylesheet' ) || false !== stripos( $content, '<?xml-stylesheet' ) ); $has_html5_doctype = ( preg_match( '/^<!DOCTYPE.+html>/i', ltrim( $content ) ) > 0 ); $has_noptimize_page = ( false !== stripos( $content, '<!-- noptimize-page -->' ) ); if ( $has_no_html_tag ) { // Can't be valid amp markup without an html tag preceding it. $is_amp_markup = false; } else { $is_amp_markup = self::is_amp_markup( $content ); } // If it's not html, or if it's amp or contains xsl stylesheets we don't touch it. if ( $has_no_html_tag && ! $has_html5_doctype || $is_amp_markup || $has_xsl_stylesheet || $has_noptimize_page ) { $valid = false; } return $valid; } /** * Returns true if given $content is considered to be AMP markup. * This is far from actual validation against AMP spec, but it'll do for now. * * @param string $content Markup to check. * * @return bool */ public static function is_amp_markup( $content ) { // Short-circuit if the page is already AMP from the start. if ( preg_match( sprintf( '#^(?:<!.*?>|\s+)*+<html(?=\s)[^>]*?\s(%1$s|%2$s|%3$s)(\s|=|>)#is', 'amp', "\xE2\x9A\xA1", // From \AmpProject\Attribute::AMP_EMOJI. "\xE2\x9A\xA1\xEF\xB8\x8F" // From \AmpProject\Attribute::AMP_EMOJI_ALT, per https://github.com/ampproject/amphtml/issues/25990. ), $content ) ) { return true; } // Or else short-circuit if the AMP plugin will be processing the output to be an AMP page. if ( function_exists( 'amp_is_request' ) ) { return amp_is_request(); // For AMP plugin v2.0+. } elseif ( function_exists( 'is_amp_endpoint' ) ) { return is_amp_endpoint(); // For older/other AMP plugins (still supported in 2.0 as an alias). } return false; } /** * Processes/optimizes the output-buffered content and returns it. * If the content is not processable, it is returned unmodified. * * @param string $content Buffered content. * * @return string */ public function end_buffering( $content ) { // Bail early without modifying anything if we can't handle the content. if ( ! $this->is_valid_buffer( $content ) ) { return $content; } $conf = autoptimizeConfig::instance(); // Determine what needs to be ran. $classes = array(); if ( $conf->get( 'autoptimize_js' ) ) { $classes[] = 'autoptimizeScripts'; } if ( $conf->get( 'autoptimize_css' ) ) { $classes[] = 'autoptimizeStyles'; } if ( $conf->get( 'autoptimize_html' ) ) { $classes[] = 'autoptimizeHTML'; } $classoptions = array( 'autoptimizeScripts' => array( 'aggregate' => $conf->get( 'autoptimize_js_aggregate' ), 'defer_not_aggregate' => $conf->get( 'autoptimize_js_defer_not_aggregate' ), 'defer_inline' => $conf->get( 'autoptimize_js_defer_inline' ), 'justhead' => $conf->get( 'autoptimize_js_justhead' ), 'forcehead' => $conf->get( 'autoptimize_js_forcehead' ), 'trycatch' => $conf->get( 'autoptimize_js_trycatch' ), 'js_exclude' => $conf->get( 'autoptimize_js_exclude' ), 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ), 'include_inline' => $conf->get( 'autoptimize_js_include_inline' ), 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ), ), 'autoptimizeStyles' => array( 'aggregate' => $conf->get( 'autoptimize_css_aggregate' ), 'justhead' => $conf->get( 'autoptimize_css_justhead' ), 'datauris' => $conf->get( 'autoptimize_css_datauris' ), 'defer' => $conf->get( 'autoptimize_css_defer' ), 'defer_inline' => $conf->get( 'autoptimize_css_defer_inline' ), 'inline' => $conf->get( 'autoptimize_css_inline' ), 'css_exclude' => $conf->get( 'autoptimize_css_exclude' ), 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ), 'include_inline' => $conf->get( 'autoptimize_css_include_inline' ), 'nogooglefont' => $conf->get( 'autoptimize_css_nogooglefont' ), 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ), ), 'autoptimizeHTML' => array( 'keepcomments' => $conf->get( 'autoptimize_html_keepcomments' ), 'minify_inline' => $conf->get( 'autoptimize_html_minify_inline' ), ), ); $content = apply_filters( 'autoptimize_filter_html_before_minify', $content ); // Run the classes! foreach ( $classes as $name ) { $instance = new $name( $content ); if ( $instance->read( $classoptions[ $name ] ) ) { $instance->minify(); $instance->cache(); $content = $instance->getcontent(); } unset( $instance ); } $content = apply_filters( 'autoptimize_html_after_minify', $content ); return $content; } public static function autoptimize_nobuffer_optimize( $html_in ) { $html_out = $html_in; if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) { $ao_speedupper = new autoptimizeSpeedupper(); } $self = new self( AUTOPTIMIZE_PLUGIN_VERSION, AUTOPTIMIZE_PLUGIN_FILE ); if ( $self->should_buffer() ) { $html_out = $self->end_buffering( $html_in ); } return $html_out; } public static function on_uninstall() { // clear the cache. autoptimizeCache::clearall(); // remove postmeta if active. if ( autoptimizeConfig::is_ao_meta_settings_active() ) { delete_post_meta_by_key( 'ao_post_optimize' ); } // remove all options. $delete_options = array( 'autoptimize_cache_clean', 'autoptimize_cache_nogzip', 'autoptimize_css', 'autoptimize_css_aggregate', 'autoptimize_css_datauris', 'autoptimize_css_justhead', 'autoptimize_css_defer', 'autoptimize_css_defer_inline', 'autoptimize_css_inline', 'autoptimize_css_exclude', 'autoptimize_html', 'autoptimize_html_keepcomments', 'autoptimize_html_minify_inline', 'autoptimize_enable_site_config', 'autoptimize_enable_meta_ao_settings', 'autoptimize_js', 'autoptimize_js_aggregate', 'autoptimize_js_defer_not_aggregate', 'autoptimize_js_defer_inline', 'autoptimize_js_exclude', 'autoptimize_js_forcehead', 'autoptimize_js_justhead', 'autoptimize_js_trycatch', 'autoptimize_version', 'autoptimize_show_adv', 'autoptimize_cdn_url', 'autoptimize_cachesize_notice', 'autoptimize_css_include_inline', 'autoptimize_js_include_inline', 'autoptimize_optimize_logged', 'autoptimize_optimize_checkout', 'autoptimize_extra_settings', 'autoptimize_service_availablity', 'autoptimize_imgopt_provider_stat', 'autoptimize_imgopt_launched', 'autoptimize_imgopt_settings', 'autoptimize_minify_excluded', 'autoptimize_cache_fallback', 'autoptimize_ccss_rules', 'autoptimize_ccss_additional', 'autoptimize_ccss_queue', 'autoptimize_ccss_viewport', 'autoptimize_ccss_finclude', 'autoptimize_ccss_rlimit', 'autoptimize_ccss_rtimelimit', 'autoptimize_ccss_noptimize', 'autoptimize_ccss_debug', 'autoptimize_ccss_key', 'autoptimize_ccss_keyst', 'autoptimize_ccss_version', 'autoptimize_ccss_loggedin', 'autoptimize_ccss_forcepath', 'autoptimize_ccss_deferjquery', 'autoptimize_ccss_domain', 'autoptimize_ccss_unloadccss', 'autoptimize_installed_before_compatibility', ); if ( ! is_multisite() ) { foreach ( $delete_options as $del_opt ) { delete_option( $del_opt ); } autoptimizeMain::remove_cronjobs(); } else { global $wpdb; $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ); $original_blog_id = get_current_blog_id(); foreach ( $blog_ids as $blog_id ) { switch_to_blog( $blog_id ); foreach ( $delete_options as $del_opt ) { delete_option( $del_opt ); } autoptimizeMain::remove_cronjobs(); } switch_to_blog( $original_blog_id ); } // Remove AO CCSS cached files and directory. $ao_ccss_dir = WP_CONTENT_DIR . '/uploads/ao_ccss/'; if ( file_exists( $ao_ccss_dir ) && is_dir( $ao_ccss_dir ) && defined( 'GLOB_BRACE' ) ) { // fixme: should check for subdirs when in multisite and remove contents of those as well. // fixme: if GLOB_BRACE is not avaible we need to remove AO_CCSS_DIR differently? array_map( 'unlink', glob( $ao_ccss_dir . '*.{css,html,json,log,zip,lock}', GLOB_BRACE ) ); rmdir( $ao_ccss_dir ); } // Remove 404-handler (although that should have been removed in clearall already). $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . 'autoptimize_404_handler.php'; if ( file_exists( $_fallback_php ) ) { unlink( $_fallback_php ); } } public static function on_deactivation() { if ( is_multisite() && is_network_admin() ) { global $wpdb; $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ); $original_blog_id = get_current_blog_id(); foreach ( $blog_ids as $blog_id ) { switch_to_blog( $blog_id ); autoptimizeMain::remove_cronjobs(); } switch_to_blog( $original_blog_id ); } else { autoptimizeMain::remove_cronjobs(); } autoptimizeCache::clearall(); } public static function remove_cronjobs() { // Remove scheduled events. foreach ( array( 'ao_cachechecker', 'ao_ccss_queue', 'ao_ccss_maintenance', 'ao_ccss_keychecker' ) as $_event ) { if ( wp_get_schedule( $_event ) ) { wp_clear_scheduled_hook( $_event ); } } } public static function notice_cache_unavailable() { echo '<div class="error"><p>'; // Translators: %s is the cache directory location. printf( esc_html__( 'Autoptimize cannot write to the cache directory (%s), please fix to enable CSS/ JS optimization!', 'autoptimize' ), AUTOPTIMIZE_CACHE_DIR ); echo '</p></div>'; } public static function notice_installed() { echo '<div class="updated"><p>'; // translators: the variables contain opening and closing <a> tags to link to the settings page. printf( esc_html__( 'Thank you for installing and activating Autoptimize. Your site is being optimized immediately, please test the frontend to ensure everything still works as expected. If needed you can change JavaScript or CSS optimization settings under %1$sSettings -> Autoptimize%2$s .', 'autoptimize' ), '<a href="options-general.php?page=autoptimize">', '</a>' ); echo '</p></div>'; } public static function notice_updated() { echo '<div class="updated"><p>'; printf( esc_html_e( 'Autoptimize has just been updated. Please %1$stest your site now%2$s and adapt Autoptimize config if needed.', 'autoptimize' ), '<strong>', '</strong>' ); echo '</p></div>'; } public static function notice_plug_imgopt() { // Translators: the URL added points to the Autopmize Extra settings. $_ao_imgopt_plug_notice = sprintf( esc_html__( 'Did you know that Autoptimize offers on-the-fly image optimization (with support for WebP and AVIF) and CDN via ShortPixel? Check out the %1$sAutoptimize Image settings%2$s to enable this option.', 'autoptimize' ), '<a href="options-general.php?page=autoptimize_imgopt">', '</a>' ); $_ao_imgopt_plug_notice = apply_filters( 'autoptimize_filter_main_imgopt_plug_notice', $_ao_imgopt_plug_notice ); $_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper(); $_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123'; $_ao_imgopt_active = autoptimizeImages::imgopt_active(); $_is_ao_settings_page = autoptimizeUtils::is_ao_settings(); if ( current_user_can( 'manage_options' ) && ! defined( 'AO_PRO_VERSION' ) && $_is_ao_settings_page && '' !== $_ao_imgopt_plug_notice && ! $_ao_imgopt_active && $_ao_imgopt_launch_ok && PAnD::is_admin_notice_active( $_ao_imgopt_plug_dismissible ) ) { echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>'; echo $_ao_imgopt_plug_notice; echo '</p></div>'; } } public static function notice_imgopt_issue() { // Translators: the URL added points to the Autopmize Extra settings. $_ao_imgopt_issue_notice = sprintf( esc_html__( 'Shortpixel reports it cannot always reach your site, which might mean some images are not optimized. You can %1$sread more about why this happens and how you can fix that problem here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/knowledge-base/article/469-i-received-an-e-mail-that-says-some-of-my-images-are-not-accessible-what-should-i-do#fullarticle" target="_blank">', '</a>' ); $_ao_imgopt_issue_notice = apply_filters( 'autoptimize_filter_main_imgopt_issue_notice', $_ao_imgopt_issue_notice ); $_ao_imgopt_issue_dismissible = 'ao-img-opt-issue-14'; $_ao_imgopt_active = autoptimizeImages::imgopt_active(); $_ao_imgopt_status = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' ); if ( is_array( $_ao_imgopt_status ) && array_key_exists( 'TemporaryRedirectOrigin', $_ao_imgopt_status ) && ( $_ao_imgopt_status['TemporaryRedirectOrigin'] === "true" || $_ao_imgopt_status['TemporaryRedirectOrigin'] === true ) ) { $_ao_imgopt_status_redirect_warning = true; } else { $_ao_imgopt_status_redirect_warning = false; } if ( current_user_can( 'manage_options' ) && $_ao_imgopt_active && $_ao_imgopt_status_redirect_warning && '' !== $_ao_imgopt_issue_notice && PAnD::is_admin_notice_active( $_ao_imgopt_issue_dismissible ) ) { echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_issue_dismissible . '"><p>'; echo $_ao_imgopt_issue_notice; echo '</p></div>'; } } public static function notice_nopagecache() { /* * Autoptimize does not do page caching (yet) but not everyone knows, so below logic tries to find out if page caching is available and if not show a notice on the AO Settings pages. * * uses helper function in autoptimizeUtils.php */ // translators: strong tags and a break. $_ao_nopagecache_notice = sprintf( esc_html__( 'It looks like your site might not have %1$spage caching%2$s which is a %1$smust-have for performance%2$s. If you are sure you have a page cache, you can close this notice.%3$sWhen in doubt check with your host if they offer this or install a free page caching plugin like for example KeyCDN Cache Enabler', 'autoptimize' ), '<strong>', '</strong>', '<br />' ); // translators: strong tags. $_ao_nopagecache_notice .= ' ' . esc_html__('or consider ', 'autoptimize') . '<strong><a href="https://autoptimize.com/pro/">Autoptimize Pro</a></strong>' . sprintf( esc_html__( ' which not only has page caching but also image optimization, critical CSS and advanced booster options %1$sto make your site significantly faster%2$s!', 'autoptimize' ), '<strong>', '</strong>' ); $_ao_nopagecache_dismissible = 'ao-nopagecache-forever'; // the notice is only shown once and will not re-appear when dismissed. $_is_ao_settings_page = autoptimizeUtils::is_ao_settings(); if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_nopagecache_dismissible ) && true === apply_filters( 'autoptimize_filter_main_show_pagecache_notice', true ) ) { if ( false === autoptimizeUtils::find_pagecache() ) { echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_nopagecache_dismissible . '"><p>'; echo $_ao_nopagecache_notice; echo '</p></div>'; } } } public static function notice_potential_conflict() { /* * Using other plugins to do CSS/ JS optimization can cause unexpected and hard to troubleshoot issues, warn users who seem to be in that situation. */ // Translators: some strong tags + the sentence will be finished with the name of the offending plugin and a final stop. $_ao_potential_conflict_notice = sprintf( esc_html__( 'It looks like you have %1$sanother plugin also doing CSS and/ or JS optimization%2$s, which can result in hard to troubleshoot %1$sconflicts%2$s. For this reason it is recommended to disable this functionality in', 'autoptimize' ), '<strong>', '</strong>' ) . ' '; $_ao_potential_conflict_dismissible = 'ao-potential-conflict-forever'; // the notice is only shown once and will not re-appear when dismissed. $_is_ao_settings_page = autoptimizeUtils::is_ao_settings(); if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_potential_conflict_dismissible ) && true === apply_filters( 'autoptimize_filter_main_show_potential_conclict_notice', true ) ) { $_potential_conflicts = autoptimizeUtils::find_potential_conflicts(); if ( false !== $_potential_conflicts ) { $_ao_potential_conflict_notice .= '<strong>' . $_potential_conflicts . '</strong>.'; echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_potential_conflict_dismissible . '"><p>'; echo $_ao_potential_conflict_notice; echo '</p></div>'; } } } } PK ��3\Q��"� � &