PluginProbe
Autoptimize / 3.1.4
Autoptimize v3.1.4
2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 All 107 releases
autoptimize / classes / autoptimizeExtra.php

autoptimizeExtra.php in Autoptimize 3.1.4, at classes/autoptimizeExtra.php

640 lines 33.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles autoptimizeExtra frontend features + admin options page
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeExtra
11 {
12 /**
13 * Options
14 *
15 * @var array
16 */
17 protected $options = array();
18
19 /**
20 * Singleton instance.
21 *
22 * @var self|null
23 */
24 protected static $instance = null;
25
26 /**
27 * Creates an instance and calls run().
28 *
29 * @param array $options Optional. Allows overriding options without having to specify them via admin options page.
30 */
31 public function __construct( $options = array() )
32 {
33 if ( empty( $options ) ) {
34 $options = self::fetch_options();
35 }
36
37 $this->options = $options;
38 }
39
40 /**
41 * Helper for getting a singleton instance. While being an
42 * anti-pattern generally, it comes in handy for now from a
43 * readability/maintainability perspective, until we get some
44 * proper dependency injection going.
45 *
46 * @return self
47 */
48 public static function instance()
49 {
50 if ( null === self::$instance ) {
51 self::$instance = new self();
52 }
53
54 return self::$instance;
55 }
56
57 public function run()
58 {
59 if ( is_admin() ) {
60 if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) {
61 add_action( 'network_admin_menu', array( $this, 'admin_menu' ) );
62 } else {
63 add_action( 'admin_menu', array( $this, 'admin_menu' ) );
64 }
65 add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_extra_tab' ) );
66 } else {
67 add_action( 'wp', array( $this, 'run_on_frontend' ) );
68 }
69 }
70
71 public function set_options( array $options )
72 {
73 $this->options = $options;
74
75 return $this;
76 }
77
78 public static function fetch_options()
79 {
80 $value = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings' );
81 if ( empty( $value ) ) {
82 // Fallback to returning defaults when no stored option exists yet.
83 $value = autoptimizeConfig::get_ao_extra_default_options();
84 }
85
86 return $value;
87 }
88
89 public function disable_emojis()
90 {
91 // Removing all actions related to emojis!
92 remove_action( 'admin_print_styles', 'print_emoji_styles' );
93 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
94 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
95 remove_action( 'wp_print_styles', 'print_emoji_styles' );
96 remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
97 remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
98 remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
99
100 // Removes TinyMCE emojis.
101 add_filter( 'tiny_mce_plugins', array( $this, 'filter_disable_emojis_tinymce' ) );
102
103 // Removes emoji dns-preftech.
104 add_filter( 'wp_resource_hints', array( $this, 'filter_remove_emoji_dns_prefetch' ), 10, 2 );
105 }
106
107 public function filter_disable_emojis_tinymce( $plugins )
108 {
109 if ( is_array( $plugins ) ) {
110 return array_diff( $plugins, array( 'wpemoji' ) );
111 } else {
112 return array();
113 }
114 }
115
116 public function filter_remove_qs( $src )
117 {
118 if ( strpos( $src, '?ver=' ) ) {
119 $src = remove_query_arg( 'ver', $src );
120 } elseif ( strpos( $src, '?v=' ) ) {
121 $src = remove_query_arg( 'v', $src );
122 }
123
124 return $src;
125 }
126
127 public function extra_async_js( $in )
128 {
129 $exclusions = array();
130 if ( ! empty( $in ) ) {
131 $exclusions = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $in ) ) ), '' );
132 }
133
134 $settings = wp_strip_all_tags( $this->options['autoptimize_extra_text_field_3'] );
135 $async = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $settings ) ) ), '' );
136 $attr = apply_filters( 'autoptimize_filter_extra_async', 'async' );
137 foreach ( $async as $k => $v ) {
138 $async[ $k ] = $attr;
139 }
140
141 // Merge exclusions & asyncs in one array and return to AO API.
142 $merged = array_merge( $exclusions, $async );
143
144 return $merged;
145 }
146
147 public function run_on_frontend()
148 {
149 // only run the Extra optimizations on frontend if general conditions
150 // for optimizations are met, this to ensure e.g. removing querystrings
151 // is not done when optimizing for logged in users is off, breaking
152 // some pagebuilders (Divi & Elementor).
153 if ( false === autoptimizeMain::should_buffer() ) {
154 return;
155 }
156
157 $options = $this->options;
158
159 // Disable emojis if specified.
160 if ( ! empty( $options['autoptimize_extra_checkbox_field_1'] ) ) {
161 $this->disable_emojis();
162 }
163
164 // Remove version query parameters.
165 if ( ! empty( $options['autoptimize_extra_checkbox_field_0'] ) ) {
166 add_filter( 'script_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
167 add_filter( 'style_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
168 }
169
170 // Avoiding conflicts of interest when async-javascript plugin is active!
171 $async_js_plugin_active = autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' );
172 if ( ! empty( $options['autoptimize_extra_text_field_3'] ) && ! $async_js_plugin_active ) {
173 add_filter( 'autoptimize_filter_js_exclude', array( $this, 'extra_async_js' ), 10, 1 );
174 }
175
176 // Optimize google fonts!
177 if ( ! empty( $options['autoptimize_extra_radio_field_4'] ) && ( '1' !== $options['autoptimize_extra_radio_field_4'] ) ) {
178 add_filter( 'wp_resource_hints', array( $this, 'filter_remove_gfonts_dnsprefetch' ), 10, 2 );
179 add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_google_fonts' ), 10, 1 );
180 add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_google_fonts' ), 10, 1 );
181
182 if ( '2' === $options['autoptimize_extra_radio_field_4'] ) {
183 // remove Google Fonts, adding filters to also remove Google Fonts from 3rd party themes/ plugins.
184 // inspired by https://wordpress.org/plugins/disable-remove-google-fonts/.
185 remove_action( 'wp_footer', 'et_builder_print_font' ); // Divi.
186 remove_action( 'wp_footer', array( 'RevSliderFront', 'load_google_fonts' ) ); // Revslider.
187 add_filter( 'elementor/frontend/print_google_fonts', '__return_false' ); // Elementor.
188 add_filter( 'fl_builder_google_fonts_pre_enqueue', '__return_empty_array' ); // Beaver Builder.
189 }
190 }
191
192 // Preconnect!
193 if ( ! empty( $options['autoptimize_extra_text_field_2'] ) || has_filter( 'autoptimize_extra_filter_tobepreconn' ) ) {
194 add_filter( 'wp_resource_hints', array( $this, 'filter_preconnect' ), 10, 2 );
195 }
196
197 // Preload!
198 if ( ! empty( $options['autoptimize_extra_text_field_7'] ) || has_filter( 'autoptimize_filter_extra_tobepreloaded' ) || ! empty( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) {
199 add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_preload' ), 10, 2 );
200 }
201
202 // Remove global styles.
203 if ( ! empty( $options['autoptimize_extra_checkbox_field_8'] ) ) {
204 $this->disable_global_styles();
205 }
206 }
207
208 public function filter_remove_emoji_dns_prefetch( $urls, $relation_type )
209 {
210 $emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/' );
211
212 return $this->filter_remove_dns_prefetch( $urls, $relation_type, $emoji_svg_url );
213 }
214
215 public function filter_remove_gfonts_dnsprefetch( $urls, $relation_type )
216 {
217 return $this->filter_remove_dns_prefetch( $urls, $relation_type, 'fonts.googleapis.com' );
218 }
219
220 public function filter_remove_dns_prefetch( $urls, $relation_type, $url_to_remove )
221 {
222 $url_to_remove = (string) $url_to_remove;
223
224 if ( ! empty( $url_to_remove ) && 'dns-prefetch' === $relation_type ) {
225 $cnt = 0;
226 foreach ( $urls as $url ) {
227 if ( false !== strpos( $url, $url_to_remove ) ) {
228 unset( $urls[ $cnt ] );
229 }
230 $cnt++;
231 }
232 }
233
234 return $urls;
235 }
236
237 public function filter_optimize_google_fonts( $in )
238 {
239 // Extract fonts, partly based on wp rocket's extraction code.
240 $markup = preg_replace( '/<!--(.*)-->/Uis', '', $in );
241 preg_match_all( '#<link(?:\s+(?:(?!href\s*=\s*)[^>])+)?(?:\s+href\s*=\s*([\'"])((?:https?:)?\/\/fonts\.googleapis\.com\/css(?:(?!\1).)+)\1)(?:\s+[^>]*)?>#iU', $markup, $matches );
242
243 $fonts_collection = array();
244 if ( ! $matches[2] ) {
245 return $in;
246 }
247
248 // Store them in $fonts array.
249 $i = 0;
250 foreach ( $matches[2] as $font ) {
251 if ( ! preg_match( '/rel=["\']dns-prefetch["\']/', $matches[0][ $i ] ) ) {
252 // Get fonts name.
253 $font = str_replace( array( '%7C', '%7c' ), '|', $font );
254 if ( strpos( $font, 'fonts.googleapis.com/css2' ) !== false ) {
255 // (Somewhat) change Google Fonts APIv2 syntax back to v1.
256 // todo: support for 100..900
257 $font = rawurldecode( $font );
258 $font = str_replace( array( 'css2?', 'ital,wght@', 'wght@', 'ital@', '0,', '1,', ':1', ';', '&family=' ), array( 'css?', '', '', '', '', 'italic', ':italic', ',', '%7C' ), $font );
259 }
260 $font = explode( 'family=', $font );
261 $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
262 // Add font to $fonts[$i] but make sure not to pollute with an empty family!
263 $_thisfont = array_values( array_filter( explode( '|', reset( $font ) ) ) );
264 if ( ! empty( $_thisfont ) ) {
265 $fonts_collection[ $i ]['fonts'] = $_thisfont;
266 // And add subset if any!
267 $subset = ( is_array( $font ) ) ? end( $font ) : '';
268 if ( false !== strpos( $subset, 'subset=' ) ) {
269 $subset = str_replace( array( '%2C', '%2c' ), ',', $subset );
270 $subset = explode( 'subset=', $subset );
271 $fonts_collection[ $i ]['subsets'] = explode( ',', $subset[1] );
272 }
273 }
274 // And remove Google Fonts.
275 $in = str_replace( $matches[0][ $i ], '', $in );
276 }
277 $i++;
278 }
279
280 $options = $this->options;
281 $fonts_markup = '';
282 if ( '2' === $options['autoptimize_extra_radio_field_4'] ) {
283 // Remove Google Fonts.
284 unset( $fonts_collection );
285 return $in;
286 } elseif ( '3' === $options['autoptimize_extra_radio_field_4'] || '5' === $options['autoptimize_extra_radio_field_4'] ) {
287 // Aggregate & link!
288 $fonts_string = '';
289 $subset_string = '';
290 foreach ( $fonts_collection as $font ) {
291 $fonts_string .= '|' . trim( implode( '|', $font['fonts'] ), '|' );
292 if ( ! empty( $font['subsets'] ) ) {
293 $subset_string .= ',' . trim( implode( ',', $font['subsets'] ), ',' );
294 }
295 }
296
297 if ( ! empty( $subset_string ) ) {
298 $subset_string = str_replace( ',', '%2C', ltrim( $subset_string, ',' ) );
299 $fonts_string = $fonts_string . '&#038;subset=' . $subset_string;
300 }
301
302 $fonts_string = apply_filters( 'autoptimize_filter_extra_gfont_fontstring', str_replace( '|', '%7C', ltrim( $fonts_string, '|' ) ) );
303 // only add display parameter if there is none in $fonts_string (by virtue of the filter).
304 if ( strpos( $fonts_string, 'display=' ) === false ) {
305 $fonts_string .= apply_filters( 'autoptimize_filter_extra_gfont_display', '&amp;display=swap' );
306 }
307
308 if ( ! empty( $fonts_string ) ) {
309 if ( '5' === $options['autoptimize_extra_radio_field_4'] ) {
310 $rel_string = 'rel="stylesheet" media="print" onload="' . autoptimizeConfig::get_ao_css_preload_onload() . '"';
311 } else {
312 $rel_string = 'rel="stylesheet"';
313 }
314 $fonts_markup = '<link ' . $rel_string . ' id="ao_optimized_gfonts" href="https://fonts.googleapis.com/css?family=' . $fonts_string . '" />';
315 }
316 } elseif ( '4' === $options['autoptimize_extra_radio_field_4'] ) {
317 // Aggregate & load async (webfont.js impl.)!
318 $fonts_array = array();
319 foreach ( $fonts_collection as $_fonts ) {
320 if ( ! empty( $_fonts['subsets'] ) ) {
321 $_subset = implode( ',', $_fonts['subsets'] );
322 foreach ( $_fonts['fonts'] as $key => $_one_font ) {
323 $_one_font = $_one_font . ':' . $_subset;
324 $_fonts['fonts'][ $key ] = $_one_font;
325 }
326 }
327 $fonts_array = array_merge( $fonts_array, $_fonts['fonts'] );
328 }
329
330 $fonts_array = array_map( 'urldecode', $fonts_array );
331 $fonts_array = array_map(
332 function( $_f ) {
333 return trim( $_f, ',' );
334 },
335 $fonts_array
336 );
337
338 // type attrib on <script not added by default.
339 $type_js = '';
340 if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) {
341 $type_js = 'type="text/javascript" ';
342 }
343
344 $fonts_markup = '<script ' . $type_js . 'data-cfasync="false" id="ao_optimized_gfonts_config">WebFontConfig={google:{families:' . wp_json_encode( $fonts_array ) . ' },classes:false, events:false, timeout:1500};</script>';
345 $fonts_library_markup = '<script ' . $type_js . 'data-cfasync="false" id="ao_optimized_gfonts_webfontloader">(function() {var wf = document.createElement(\'script\');wf.src=\'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js\';wf.type=\'text/javascript\';wf.async=\'true\';var s=document.getElementsByTagName(\'script\')[0];s.parentNode.insertBefore(wf, s);})();</script>';
346 $in = substr_replace( $in, $fonts_library_markup . '</head>', strpos( $in, '</head>' ), strlen( '</head>' ) );
347 }
348
349 // Replace back in markup.
350 $inject_point = apply_filters( 'autoptimize_filter_extra_gfont_injectpoint', '<link' );
351 $out = substr_replace( $in, $fonts_markup . $inject_point, strpos( $in, $inject_point ), strlen( $inject_point ) );
352 unset( $fonts_collection );
353
354 return $out;
355 }
356
357 public function filter_preconnect( $hints, $relation_type )
358 {
359 $options = $this->options;
360 $preconns = array();
361
362 // Get settings and store in array.
363 if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) {
364 $preconns = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_2'] ) ) ) );
365 }
366 $preconns = apply_filters( 'autoptimize_extra_filter_tobepreconn', $preconns );
367
368 // Walk array, extract domain and add to new array with crossorigin attribute.
369 foreach ( $preconns as $preconn ) {
370 $domain = '';
371 $parsed = parse_url( $preconn );
372 if ( is_array( $parsed ) && ! empty( $parsed['host'] ) && empty( $parsed['scheme'] ) ) {
373 $domain = '//' . $parsed['host'];
374 } elseif ( is_array( $parsed ) && ! empty( $parsed['host'] ) ) {
375 $domain = $parsed['scheme'] . '://' . $parsed['host'];
376 }
377
378 if ( ! empty( $domain ) ) {
379 $hint = array( 'href' => $domain );
380 // Fonts don't get preconnected unless crossorigin flag is set, non-fonts don't get preconnected if origin flag is set
381 // so hardcode fonts.gstatic.com to come with crossorigin and have filter to add other domains if needed.
382 $crossorigins = apply_filters( 'autoptimize_extra_filter_preconn_crossorigin', array( 'https://fonts.gstatic.com' ) );
383 if ( in_array( $domain, $crossorigins ) ) {
384 $hint['crossorigin'] = 'anonymous';
385 }
386 $new_hints[] = $hint;
387 }
388 }
389
390 // Merge in WP's preconnect hints.
391 if ( 'preconnect' === $relation_type && ! empty( $new_hints ) ) {
392 $hints = array_merge( $hints, $new_hints );
393 }
394
395 return $hints;
396 }
397
398 public function filter_preconnect_google_fonts( $in )
399 {
400 if ( '2' !== $this->options['autoptimize_extra_radio_field_4'] ) {
401 // Preconnect to fonts.gstatic.com unless we remove gfonts.
402 $in[] = 'https://fonts.gstatic.com';
403 }
404
405 if ( '4' === $this->options['autoptimize_extra_radio_field_4'] ) {
406 // Preconnect even more hosts for webfont.js!
407 $in[] = 'https://ajax.googleapis.com';
408 $in[] = 'https://fonts.googleapis.com';
409 }
410
411 return $in;
412 }
413
414 public function filter_preload( $in ) {
415 // make array from comma separated list.
416 $options = $this->options;
417 $preloads = array();
418 if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) {
419 $preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_7'] ) ) ) );
420 }
421
422 if ( false === autoptimizeImages::imgopt_active() && false === autoptimizeImages::should_lazyload_wrapper() ) {
423 // only do this here if imgopt/ lazyload are not active?
424 $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
425 if ( ! empty( $metabox_preloads ) ) {
426 $preloads = array_merge( $preloads, $metabox_preloads );
427 }
428 }
429
430 $preloads = apply_filters( 'autoptimize_filter_extra_tobepreloaded', $preloads );
431
432 // immediately return if nothing to be preloaded.
433 if ( empty( $preloads ) ) {
434 return $in;
435 }
436
437 // iterate through array and add preload link to tmp string.
438 $preload_output = '';
439 foreach ( $preloads as $preload ) {
440 if ( filter_var( $preload, FILTER_VALIDATE_URL ) !== $preload ) {
441 continue;
442 }
443 $preload = esc_url_raw( $preload );
444 $crossorigin = '';
445 $preload_as = '';
446 $mime_type = '';
447 $_preload = strtok( $preload, '?' );
448
449 if ( autoptimizeUtils::str_ends_in( $_preload, '.css' ) ) {
450 $preload_as = 'style';
451 } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.js' ) ) {
452 $preload_as = 'script';
453 } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.woff' ) || autoptimizeUtils::str_ends_in( $_preload, '.woff2' ) || autoptimizeUtils::str_ends_in( $_preload, '.ttf' ) || autoptimizeUtils::str_ends_in( $_preload, '.eot' ) || autoptimizeUtils::str_ends_in( $_preload, '.otf' ) ) {
454 $preload_as = 'font';
455 $crossorigin = ' crossorigin';
456 $mime_type = ' type="font/' . pathinfo( $_preload, PATHINFO_EXTENSION ) . '"';
457 if ( ' type="font/eot"' === $mime_type ) {
458 $mime_type = 'application/vnd.ms-fontobject';
459 }
460 } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.jpeg' ) || autoptimizeUtils::str_ends_in( $_preload, '.jpg' ) || autoptimizeUtils::str_ends_in( $_preload, '.webp' ) || autoptimizeUtils::str_ends_in( $_preload, '.png' ) || autoptimizeUtils::str_ends_in( $_preload, '.gif' ) || autoptimizeUtils::str_ends_in( $_preload, '.svg' ) ) {
461 $preload_as = 'image';
462 } else {
463 $preload_as = 'other';
464 }
465
466 $preload_output .= '<link rel="preload" href="' . $preload . '" as="' . $preload_as . '"' . $mime_type . $crossorigin . '>';
467 }
468 $preload_output = apply_filters( 'autoptimize_filter_extra_preload_output', $preload_output );
469
470 return $this->inject_preloads( $preload_output, $in );
471 }
472
473 public static function inject_preloads( $preloads, $html ) {
474 // add string to head (before first link node by default).
475 $preload_inject = apply_filters( 'autoptimize_filter_extra_preload_inject', '<link' );
476 $position = autoptimizeUtils::strpos( $html, $preload_inject );
477
478 return autoptimizeUtils::substr_replace( $html, $preloads . $preload_inject, $position, strlen( $preload_inject ) );
479 }
480
481 public function disable_global_styles()
482 {
483 remove_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' );
484 remove_action( 'wp_footer', 'wp_enqueue_global_styles', 1 );
485 remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
486
487 if ( true === apply_filters( 'autoptimize_filter_extra_global_styles_and_block_css', true ) ) {
488 add_action(
489 'wp_enqueue_scripts',
490 function() {
491 wp_dequeue_style( 'wp-block-library' );
492 wp_dequeue_style( 'wp-block-library-theme' );
493 }
494 );
495 }
496 }
497
498 public function admin_menu()
499 {
500 // no acces if multisite and not network admin and no site config allowed.
501 if ( autoptimizeConfig::should_show_menu_tabs() ) {
502 add_submenu_page(
503 '',
504 'autoptimize_extra',
505 'autoptimize_extra',
506 'manage_options',
507 'autoptimize_extra',
508 array( $this, 'options_page' )
509 );
510 }
511 register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
512 }
513
514 public function add_extra_tab( $in )
515 {
516 if ( autoptimizeConfig::should_show_menu_tabs() ) {
517 $in = array_merge( $in, array( 'autoptimize_extra' => __( 'Extra', 'autoptimize' ) ) );
518 }
519
520 return $in;
521 }
522
523 public function options_page()
524 {
525 // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
526
527 // Working with actual option values from the database here.
528 // That way any saves are still processed as expected, but we can still
529 // override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
530 // behavior being persisted in the DB even if save is done here.
531 $options = $this->fetch_options();
532 $gfonts = $options['autoptimize_extra_radio_field_4'];
533 ?>
534 <style>
535 #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
536 #ao_settings_form .form-table th {font-weight: normal;}
537 #autoptimize_extra_descr{font-size: 120%;}
538 </style>
539 <script>document.title = "Autoptimize: <?php _e( 'Extra', 'autoptimize' ); ?> " + document.title;</script>
540 <div class="wrap">
541 <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
542 <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
543 <?php if ( 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_js' ) && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css' ) && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_html' ) && ! autoptimizeImages::imgopt_active() ) { ?>
544 <div class="notice-warning notice"><p>
545 <?php _e( 'Most of below Extra optimizations require at least one of HTML, JS, CSS or Image autoptimizations being active.', 'autoptimize' ); ?>
546 </p></div>
547 <?php } ?>
548
549 <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
550 <?php settings_fields( 'autoptimize_extra_settings' ); ?>
551 <h2><?php _e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
552 <span id='autoptimize_extra_descr'><?php _e( 'The following settings can improve your site\'s performance even more.', 'autoptimize' ); ?></span>
553 <table class="form-table">
554 <tr>
555 <th scope="row"><?php _e( 'Google Fonts', 'autoptimize' ); ?></th>
556 <td>
557 <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="1" <?php if ( ! in_array( $gfonts, array( 2, 3, 4, 5 ) ) ) { echo 'checked'; } ?> ><?php _e( 'Leave as is', 'autoptimize' ); ?><br/>
558 <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="2" <?php checked( 2, $gfonts, true ); ?> ><?php _e( 'Remove Google Fonts', 'autoptimize' ); ?><br/>
559 <?php // translators: "display:swap" should remain untranslated, will be shown in code tags. ?>
560 <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="3" <?php checked( 3, $gfonts, true ); ?> ><?php echo __( 'Combine and link in head (fonts load fast but are render-blocking)', 'autoptimize' ) . ', ' . sprintf( __( 'includes %1$sdisplay:swap%2$s.', 'autoptimize' ), '<code>', '</code>' ); ?><br/>
561 <?php // translators: "display:swap" should remain untranslated, will be shown in code tags. ?>
562 <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="5" <?php checked( 5, $gfonts, true ); ?> ><?php echo __( 'Combine and link deferred in head (fonts load late, but are not render-blocking)', 'autoptimize' ) . ', ' . sprintf( __( 'includes %1$sdisplay:swap%2$s.', 'autoptimize' ), '<code>', '</code>' ); ?><br/>
563 <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php echo __( 'Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a>', 'autoptimize' ) . ' ' . __( '(deprecated)', 'autoptimize' ); ?><br/>
564 </td>
565 </tr>
566 <tr>
567 <th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
568 <td>
569 <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_1'] ) && '1' === $options['autoptimize_extra_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Removes WordPress\' core emojis\' inline CSS, inline JavaScript, and an otherwise un-autoptimized JavaScript file.', 'autoptimize' ); ?></label>
570 </td>
571 </tr>
572 <tr>
573 <th scope="row"><?php _e( 'Remove query strings from static resources', 'autoptimize' ); ?></th>
574 <td>
575 <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_0]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_0'] ) && '1' === $options['autoptimize_extra_checkbox_field_0'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Removing query strings (or more specifically the <code>ver</code> parameter) will not improve load time, but might improve performance scores.', 'autoptimize' ); ?></label>
576 </td>
577 </tr>
578 <tr>
579 <th scope="row"><?php _e( 'Remove WordPress block CSS', 'autoptimize' ); ?></th>
580 <td>
581 <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_8]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_8'] ) && '1' === $options['autoptimize_extra_checkbox_field_8'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'WordPress adds block CSS and global styles to improve easy styling of block-based sites, but which can add a significant amount of CSS and SVG. If you are sure your site can do without the block CSS and "global styles", you can disable them here.', 'autoptimize' ); ?></label>
582 </td>
583 </tr>
584 <tr>
585 <th scope="row"><?php _e( 'Preconnect to 3rd party domains <em>(advanced users)</em>', 'autoptimize' ); ?></th>
586 <td>
587 <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_2]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_2'] ); } ?>'><br /><?php _e( 'Add 3rd party domains you want the browser to <a href="https://www.keycdn.com/support/preconnect/#primary" target="_blank">preconnect</a> to, separated by comma\'s. Make sure to include the correct protocol (HTTP or HTTPS).', 'autoptimize' ); ?></label>
588 </td>
589 </tr>
590 <tr>
591 <th scope="row"><?php _e( 'Preload specific requests <em>(advanced users)</em>', 'autoptimize' ); ?></th>
592 <td>
593 <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_7]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_7'] ); } ?>'><br /><?php _e( 'Comma-separated list with full URL\'s of to to-be-preloaded resources. To be used sparingly!', 'autoptimize' ); ?></label>
594 </td>
595 </tr>
596 <tr>
597 <th scope="row"><?php _e( 'Async Javascript-files <em>(advanced users)</em>', 'autoptimize' ); ?></th>
598 <td>
599 <?php
600 if ( autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
601 // translators: link points Async Javascript settings page.
602 printf( __( 'You have "Async JavaScript" installed, %1$sconfiguration of async javascript is best done there%2$s.', 'autoptimize' ), '<a href="' . 'options-general.php?page=async-javascript' . '">', '</a>' );
603 } else {
604 ?>
605 <input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_3]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_3', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_3'] ); } ?>'>
606 <br />
607 <?php
608 _e( 'Comma-separated list of local or 3rd party JS-files that should loaded with the <code>async</code> flag. JS-files from your own site will be automatically excluded if added here. ', 'autoptimize' );
609 // translators: %s will be replaced by a link to the "async javascript" plugin.
610 echo sprintf( __( 'Configuration of async javascript is easier and more flexible using the %s plugin.', 'autoptimize' ), '"<a href="https://wordpress.org/plugins/async-javascript" target="_blank">Async Javascript</a>"' );
611 $asj_install_url = network_admin_url() . 'plugin-install.php?s=async+javascript&tab=search&type=term';
612 echo sprintf( ' <a href="' . $asj_install_url . '">%s</a>', __( 'Click here to install and activate it.', 'autoptimize' ) );
613 }
614 ?>
615 </td>
616 </tr>
617 <tr>
618 <th scope="row"><?php _e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
619 <td>
620 <?php
621 if ( autoptimizeUtils::is_plugin_active( 'wp-youtube-lyte/wp-youtube-lyte.php' ) ) {
622 _e( 'Great, you have WP YouTube Lyte installed.', 'autoptimize' );
623 $lyte_config_url = 'options-general.php?page=lyte_settings_page';
624 echo sprintf( ' <a href="' . $lyte_config_url . '">%s</a>', __( 'Click here to configure it.', 'autoptimize' ) );
625 } else {
626 // translators: %s will be replaced by a link to "wp youtube lyte" plugin.
627 echo sprintf( __( '%s allows you to “lazy load” your videos, by inserting responsive “Lite YouTube Embeds". ', 'autoptimize' ), '<a href="https://wordpress.org/plugins/wp-youtube-lyte" target="_blank">WP YouTube Lyte</a>' );
628 $lyte_install_url = network_admin_url() . 'plugin-install.php?s=lyte&tab=search&type=term';
629 echo sprintf( ' <a href="' . $lyte_install_url . '">%s</a>', __( 'Click here to install and activate it.', 'autoptimize' ) );
630 }
631 ?>
632 </td>
633 </tr>
634 </table>
635 <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
636 </form>
637 <?php
638 }
639 }
640