| @@ -163,14 +163,13 @@ | ||
| 163 | 163 | */ |
| 164 | 164 | public function read( $options ) |
| 165 | 165 | { |
| 166 | 166 | $noptimize_css = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content ); |
| 167 | - if ( $noptimize_css ) { | |
| 167 | + if ( $noptimize_css || false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_css_optimize' )) { | |
| 168 | 168 | return false; |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | 171 | $allowlist_css = apply_filters( 'autoptimize_filter_css_allowlist', '', $this->content ); |
| 172 | - $allowlist_css = apply_filters( 'autoptimize_filter_css_whitelist', $allowlist_css, $this->content ); // fixme: to be removed in next version. | |
| 173 | 172 | if ( ! empty( $allowlist_css ) ) { |
| 174 | 173 | $this->allowlist = array_filter( array_map( 'trim', explode( ',', $allowlist_css ) ) ); |
| 175 | 174 | } |
| 176 | 175 | |
| @@ -198,8 +197,10 @@ | ||
| 198 | 197 | // Returning true for "dontaggregate" turns off aggregation. |
| 199 | 198 | if ( $this->aggregate && apply_filters( 'autoptimize_filter_css_dontaggregate', false ) ) { |
| 200 | 199 | $this->aggregate = false; |
| 201 | 200 | } |
| 201 | + // and the filter that should have been there to begin with. | |
| 202 | + $this->aggregate = apply_filters( 'autoptimize_filter_css_aggregate', $this->aggregate ); | |
| 202 | 203 | |
| 203 | 204 | // include inline? |
| 204 | 205 | if ( apply_filters( 'autoptimize_css_include_inline', $options['include_inline'] ) ) { |
| 205 | 206 | $this->include_inline = true; |
| @@ -215,16 +216,24 @@ | ||
| 215 | 216 | |
| 216 | 217 | // forcefully exclude CSS with data-noptimize attrib. |
| 217 | 218 | $this->dontmove[] = 'data-noptimize'; |
| 218 | 219 | |
| 220 | + // forcefully exclude inline CSS with ".wp-container-" which due to the random-ish nature busts AO's cache continuously. | |
| 221 | + $this->dontmove[] = '.wp-container-'; | |
| 222 | + | |
| 219 | 223 | // Should we defer css? |
| 220 | 224 | // value: true / false. |
| 221 | 225 | $this->defer = $options['defer']; |
| 222 | 226 | $this->defer = apply_filters( 'autoptimize_filter_css_defer', $this->defer, $this->content ); |
| 223 | 227 | |
| 228 | + // If page/ post check post_meta to see if optimize is off. | |
| 229 | + if ( $this->defer && false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_ccss' ) ) { | |
| 230 | + $this->defer = false; | |
| 231 | + } | |
| 232 | + | |
| 224 | 233 | // Should we inline while deferring? |
| 225 | 234 | // value: inlined CSS. |
| 226 | - $this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $options['defer_inline'], $this->content ); | |
| 235 | + $this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $this->sanitize_css( $options['defer_inline'] ), $this->content ); | |
| 227 | 236 | |
| 228 | 237 | // Should we inline? |
| 229 | 238 | // value: true / false. |
| 230 | 239 | $this->inline = $options['inline']; |
| @@ -271,16 +280,20 @@ | ||
| 271 | 280 | } elseif ( $this->ismovable( $tag ) ) { |
| 272 | 281 | // Get the media. |
| 273 | 282 | if ( false !== strpos( $tag, 'media=' ) ) { |
| 274 | 283 | preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias ); |
| 275 | - $medias = explode( ',', $medias[1] ); | |
| 276 | - $media = array(); | |
| 277 | - foreach ( $medias as $elem ) { | |
| 278 | - if ( empty( $elem ) ) { | |
| 279 | - $elem = 'all'; | |
| 284 | + if ( !empty( $medias ) ) { | |
| 285 | + $medias = explode( ',', $medias[1] ); | |
| 286 | + $media = array(); | |
| 287 | + foreach ( $medias as $elem ) { | |
| 288 | + if ( empty( $elem ) ) { | |
| 289 | + $elem = 'all'; | |
| 290 | + } | |
| 291 | + | |
| 292 | + $media[] = $elem; | |
| 280 | 293 | } |
| 281 | - | |
| 282 | - $media[] = $elem; | |
| 294 | + } else { | |
| 295 | + $media = array( 'all' ); | |
| 283 | 296 | } |
| 284 | 297 | } else { |
| 285 | 298 | // No media specified - applies to all. |
| 286 | 299 | $media = array( 'all' ); |
| @@ -354,8 +367,13 @@ | ||
| 354 | 367 | |
| 355 | 368 | if ( '' !== $new_tag ) { |
| 356 | 369 | // Optionally defer (preload) non-aggregated CSS. |
| 357 | 370 | $new_tag = $this->optionally_defer_excluded( $new_tag, $url ); |
| 371 | + | |
| 372 | + // Check if we still need to CDN (esp. for already minified resources). | |
| 373 | + if ( ! empty( $this->cdn_url ) || has_filter( 'autoptimize_filter_base_replace_cdn' ) ) { | |
| 374 | + $new_tag = str_replace( $url, $this->url_replace_cdn( $url ), $new_tag ); | |
| 375 | + } | |
| 358 | 376 | } |
| 359 | 377 | |
| 360 | 378 | // And replace! |
| 361 | 379 | if ( ( '' !== $new_tag && $new_tag !== $tag ) || ( '' === $new_tag && apply_filters( 'autoptimize_filter_css_remove_empty_files', false ) ) ) { |
| @@ -472,9 +490,9 @@ | ||
| 472 | 490 | |
| 473 | 491 | private function check_datauri_exclude_list( $url ) |
| 474 | 492 | { |
| 475 | 493 | static $exclude_list = null; |
| 476 | - $no_datauris = array(); | |
| 494 | + static $no_datauris = array(); | |
| 477 | 495 | |
| 478 | 496 | // Again, skip doing certain stuff repeatedly when loop-called. |
| 479 | 497 | if ( null === $exclude_list ) { |
| 480 | 498 | $exclude_list = apply_filters( 'autoptimize_filter_css_datauri_exclude', '' ); |
| @@ -854,9 +872,9 @@ | ||
| 854 | 872 | $code = self::build_injectlater_marker( $path, md5( $code ) ); |
| 855 | 873 | } |
| 856 | 874 | |
| 857 | 875 | if ( ! empty( $code ) ) { |
| 858 | - $tmp_thiscss = preg_replace( '#(/\*FILESTART\*/.*)' . preg_quote( $import, '#' ) . '#Us', '/*FILESTART2*/' . $code . '$1', $thiscss ); | |
| 876 | + $tmp_thiscss = str_replace( $import, stripcslashes( $code ), $thiscss ); | |
| 859 | 877 | if ( ! empty( $tmp_thiscss ) ) { |
| 860 | 878 | $thiscss = $tmp_thiscss; |
| 861 | 879 | $import_ok = true; |
| 862 | 880 | unset( $tmp_thiscss ); |
| @@ -1026,9 +1044,9 @@ | ||
| 1026 | 1044 | // Add the stylesheet either deferred (import at bottom) or normal links in head. |
| 1027 | 1045 | if ( $this->defer && 'print' !== $media ) { |
| 1028 | 1046 | $preload_onload = autoptimizeConfig::get_ao_css_preload_onload( $media ); |
| 1029 | 1047 | |
| 1030 | - $preload_css_block .= '<link rel="stylesheet" media="print" href="' . $url . '" onload="' . $preload_onload . '" />'; | |
| 1048 | + $preload_css_block .= apply_filters( 'autoptimize_filter_css_single_deferred_link', '<link rel="stylesheet" media="print" href="' . $url . '" onload="' . $preload_onload . '" />' ); | |
| 1031 | 1049 | if ( apply_filters( 'autoptimize_fitler_css_preload_and_print', false ) ) { |
| 1032 | 1050 | $preload_css_block = '<link rel="preload" as="stylesheet" href="' . $url . '"/>' . $preload_css_block; |
| 1033 | 1051 | } |
| 1034 | 1052 | $noscript_css_block .= '<link ' . $type_css . 'media="' . $media . '" href="' . $url . '" rel="stylesheet" />'; |
| @@ -1207,8 +1225,15 @@ | ||
| 1207 | 1225 | { |
| 1208 | 1226 | $contents = $this->prepare_minify_single( $filepath ); |
| 1209 | 1227 | |
| 1210 | 1228 | if ( empty( $contents ) ) { |
| 1229 | + // if aggregate is off and CCSS is used but all files are minified already, then we | |
| 1230 | + // must make sure the autoptimize_action_css_hash action still fires for CCSS's sake. | |
| 1231 | + $ao_ccss_key = get_option( 'autoptimize_ccss_key', '' ); | |
| 1232 | + if ( false === $this->aggregate && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) { | |
| 1233 | + $hash = 'single_' . md5( file_get_contents( $filepath ) ); | |
| 1234 | + do_action( 'autoptimize_action_css_hash', $hash ); | |
| 1235 | + } | |
| 1211 | 1236 | return false; |
| 1212 | 1237 | } |
| 1213 | 1238 | |
| 1214 | 1239 | // Check cache. |
| @@ -1273,6 +1298,26 @@ | ||
| 1273 | 1298 | |
| 1274 | 1299 | public function getOption( $name ) |
| 1275 | 1300 | { |
| 1276 | 1301 | return $this->options[ $name ]; |
| 1302 | + } | |
| 1303 | + | |
| 1304 | + /** | |
| 1305 | + * Sanitize user-provided CSS. | |
| 1306 | + * | |
| 1307 | + * For now just strip_tags (the WordPress way) and preg_replace to escape < in certain cases but might do full CSS escaping in the future, see: | |
| 1308 | + * https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#rule-4-css-encode-and-strictly-validate-before-inserting-untrusted-data-into-html-style-property-values | |
| 1309 | + * https://github.com/twigphp/Twig/blob/3.x/src/Extension/EscaperExtension.php#L300-L319 | |
| 1310 | + * https://github.com/laminas/laminas-escaper/blob/2.8.x/src/Escaper.php#L205-L221 | |
| 1311 | + * | |
| 1312 | + * @param string $css the to be sanitized CSS | |
| 1313 | + * @return string sanitized CSS. | |
| 1314 | + */ | |
| 1315 | + public static function sanitize_css( $css ) | |
| 1316 | + { | |
| 1317 | + $css = wp_strip_all_tags( $css ); | |
| 1318 | + if ( strpos( $css, '<' ) !== false ) { | |
| 1319 | + $css = preg_replace( '#<(\/?\w+)#', '\00003C$1', $css ); | |
| 1320 | + } | |
| 1321 | + return $css; | |
| 1277 | 1322 | } |
| 1278 | 1323 | } |