Completed
Push — master ( 32b021...6f33a8 )
by frank
03:07
created

autoptimizeExtra.php ➔ autoptimize_extra_disable_emojis()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
// initialize
5
if ( is_admin() ) {
6
    add_action( 'admin_menu', 'autoptimize_extra_admin' );
7
    add_filter( 'autoptimize_filter_settingsscreen_tabs','add_autoptimize_extra_tab' );
8
} else {
9
    autoptimize_extra_init();
10
}
11
12
// get option
13
function autoptimize_extra_get_options() {
14
    $_default_val = 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"=>"");
15
    $_option_val = get_option( 'autoptimize_extra_settings' );
16
    if (empty($_option_val)) {
17
        $_option_val = $_default_val;
18
    }
19
    return $_option_val;
20
}
21
22
// frontend init
23
function autoptimize_extra_init() {
24
    $autoptimize_extra_options = autoptimize_extra_get_options();
25
26
    /* disable emojis */
27
    if ($autoptimize_extra_options['autoptimize_extra_checkbox_field_1']) {
28
        autoptimize_extra_disable_emojis();
29
    }
30
    
31
    /* remove version from query string */
32
    if ($autoptimize_extra_options['autoptimize_extra_checkbox_field_0']) {
33
        add_filter( 'script_loader_src', 'autoptimize_extra_remove_qs', 15, 1 );
34
        add_filter( 'style_loader_src', 'autoptimize_extra_remove_qs', 15, 1 );
35
    }
36
37
    /* async JS */
38
    if (!empty($autoptimize_extra_options['autoptimize_extra_text_field_3'])) {
39
        add_filter('autoptimize_filter_js_exclude','autoptimize_extra_async_js',10,1);
40
    }
41
42
    /* optimize google fonts */
43
    if ( !empty( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] ) && ( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] != "1" ) ) {
44
        if ( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] == "2" ) {
45
            add_filter('autoptimize_filter_css_removables','autoptimize_extra_remove_gfonts',10,1);
46
        } else {
47
            add_filter('autoptimize_html_after_minify','autoptimize_extra_gfonts',10,1);
48
            add_filter('autoptimize_extra_filter_tobepreconn','autoptimize_extra_preconnectgooglefonts',10,1);
49
        }
50
    }
51
    
52
    /* preconnect */
53
    if ( !empty($autoptimize_extra_options['autoptimize_extra_text_field_2']) || has_filter('autoptimize_extra_filter_tobepreconn') ) {
54
        add_filter( 'wp_resource_hints', 'autoptimize_extra_preconnect', 10, 2 );
55
    }
56
}
57
58
// disable emoji's functions
59
function autoptimize_extra_disable_emojis() {
60
    // all actions related to emojis
61
    remove_action( 'admin_print_styles', 'print_emoji_styles' );
62
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
63
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
64
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
65
    remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
66
    remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
67
    remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
68
69
    // filter to remove TinyMCE emojis
70
    add_filter( 'tiny_mce_plugins', 'autoptimize_extra_disable_emojis_tinymce' );
71
}
72
73
function autoptimize_extra_disable_emojis_tinymce( $plugins ) {
74
    if ( is_array( $plugins ) ) {
75
        return array_diff( $plugins, array( 'wpemoji' ) );
76
    } else {
77
        return array();
78
    }
79
}
80
81
// remove query string function
82
function autoptimize_extra_remove_qs( $src ) {
83
    if ( strpos($src, '?ver=') ) {
84
            $src = remove_query_arg( 'ver', $src );
85
    }
86
    return $src;
87
}
88
89
// async function
90
function autoptimize_extra_async_js($in) {
91
    $autoptimize_extra_options = autoptimize_extra_get_options();
92
    
93
    // get exclusions
94
    $AO_JSexclArrayIn = array();
95 View Code Duplication
    if (!empty($in)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
        $AO_JSexclArrayIn = array_fill_keys(array_filter(array_map('trim',explode(",",$in))),"");
97
    }
98
    
99
    // get asyncs
100
    $_fromSetting = $autoptimize_extra_options['autoptimize_extra_text_field_3'];
101
    $AO_asynced_JS = array_fill_keys(array_filter(array_map('trim',explode(",",$_fromSetting))),"");
102
    foreach ($AO_asynced_JS as $JSkey => $JSvalue) {
103
        $AO_asynced_JS[$JSkey] = "async";
104
    }
105
    
106
    // merge exclusions & asyncs in one array and return to AO API
107
    $AO_excl_w_async = array_merge( $AO_JSexclArrayIn, $AO_asynced_JS );
108
    return $AO_excl_w_async;
109
}
110
111
// preconnect function
112
function autoptimize_extra_preconnect($hints, $relation_type) {
113
    $autoptimize_extra_options = autoptimize_extra_get_options();
114
    
115
    // get setting and store in array
116
    $_to_be_preconnected = array_filter(array_map('trim',explode(",",$autoptimize_extra_options['autoptimize_extra_text_field_2'])));
117
    $_to_be_preconnected = apply_filters( 'autoptimize_extra_filter_tobepreconn', $_to_be_preconnected );
118
119
    // walk array, extract domain and add to new array with crossorigin attribute
120
    foreach ($_to_be_preconnected as $_preconn_single) {
121
        $_preconn_parsed = parse_url($_preconn_single);
122
        
123
        if ( is_array($_preconn_parsed) && empty($_preconn_parsed['scheme']) ) {
124
            $_preconn_domain = "//".$_preconn_parsed['host'];
125
        } else if ( is_array($_preconn_parsed) ) {
126
            $_preconn_domain = $_preconn_parsed['scheme']."://".$_preconn_parsed['host'];
127
        }
128
        
129
        if ( !empty($_preconn_domain) ) {
130
            $_preconn_hint = array('href' => $_preconn_domain);
131
            // fonts don't get preconnected unless crossorigin flag is set, non-fonts don't get preconnected if origin flag is set
132
            // so hardcode fonts.gstatic.com to come with crossorigin and have filter to add other domains if needed
133
            $_preconn_crossorigin = apply_filters( 'autoptimize_extra_filter_preconn_crossorigin', array('https://fonts.gstatic.com') );
134
            if ( in_array( $_preconn_domain, $_preconn_crossorigin ) ) {
135
                $_preconn_hint['crossorigin'] = 'anonymous';
136
            }
137
            $_new_hints[] = $_preconn_hint;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$_new_hints was never initialized. Although not strictly required by PHP, it is generally a good practice to add $_new_hints = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
138
        }
139
    }
140
141
    // merge in wordpress' preconnect hints
142
    if ( 'preconnect' === $relation_type && !empty($_new_hints) ) {
143
        $hints = array_merge($hints, $_new_hints);      
144
    }
145
    
146
    return $hints;
147
}
148
149
// google font functions
150
function autoptimize_extra_remove_gfonts($in) { 
151
    // simply remove google fonts
152
    return $in.", fonts.googleapis.com"; 
153
}
154
155
function autoptimize_extra_gfonts($in) {
156
    $autoptimize_extra_options = autoptimize_extra_get_options();
157
    
158
    // extract fonts, partly based on wp rocket's extraction code
159
    $_without_comments = preg_replace( '/<!--(.*)-->/Uis', '', $in );
160
    preg_match_all( '#<link(?:\s+(?:(?!href\s*=\s*)[^>])+)?(?:\s+href\s*=\s*([\'"])((?:https?:)?\/\/fonts\.googleapis\.com\/css(?:(?!\1).)+)\1)(?:\s+[^>]*)?>#iU', $_without_comments, $matches );
161
162
    $i = 0;
163
    $fontsCollection = array();
164
    if ( ! $matches[2] ) {
165
        return $in;
166
    }
167
    
168
    // store them in $fonts array
169
    foreach ( $matches[2] as $font ) {
170
        if ( ! preg_match( '/rel=["\']dns-prefetch["\']/', $matches[0][ $i ] ) ) {
171
            // Get fonts name.
172
            $font = str_replace( array( '%7C', '%7c' ) , '|', $font );
173
            $font = explode( 'family=', $font );
174
            $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
175
            // Add font to $fonts[$i] but make sure not to pollute with an empty family
176
            $_thisfont = array_values( array_filter( explode( '|', reset( $font ) ) ) );
177
            if ( !empty($_thisfont) ) {
178
                $fontsCollection[$i]["fonts"] = $_thisfont;
179
                // And add subset if any
180
                $subset = ( is_array( $font ) ) ? end( $font ) : '';
181
                if ( false !== strpos( $subset, 'subset=' ) ) {
182
                    $subset = explode( 'subset=', $subset );
183
                    $fontsCollection[$i]["subsets"] = explode( ',', $subset[1] );
184
                }
185
            }
186
            // And remove Google Fonts.
187
            $in = str_replace( $matches[0][ $i ], '', $in );
188
        }
189
        $i++;
190
    }
191
192
    if ( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] == "3" ) {
193
        // aggregate & link
194
        $_fontsString="";
195
        foreach ($fontsCollection as $font) {
196
            $_fontsString .= '|'.trim( implode( '|' , $font["fonts"] ), '|' );
197
            if ( !empty( $font["subsets"] ) ) {
198
                $subsetString .= implode( ',', $font["subsets"] ); 
0 ignored issues
show
Bug introduced by
The variable $subsetString does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
199
            }
200
        }
201
                    
202
        if (!empty($subsetString)) {
203
            $_fontsString = $_fontsString."#038;subset=".$subsetString;
204
        }
205
206
        $_fontsString = str_replace( '|', '%7C', ltrim($_fontsString,'|') );
207
        
208
        if ( ! empty( $_fontsString ) ) {
209
            $_fontsOut = '<link rel="stylesheet" id="ao_optimized_gfonts" href="https://fonts.googleapis.com/css?family=' . $_fontsString . '" />';
210
        }
211
    } else if ( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] == "4" ) {
212
        // aggregate & load async (webfont.js impl.)
213
        $_fontsArray = array();
214
        foreach ($fontsCollection as $_fonts) {
215
            if ( !empty( $_fonts["subsets"] ) ) {
216
                $_subset = implode(",",$_fonts["subsets"]);
217
                foreach ($_fonts["fonts"] as $key => $_one_font) {
218
                    $_one_font = $_one_font.":".$_subset;
219
                    $_fonts["fonts"][$key] = $_one_font;
220
                } 
221
            }
222
            $_fontsArray = array_merge($_fontsArray, $_fonts["fonts"]);
223
        }
224
        
225
        $_fontsOut = '<script data-cfasync="false" type="text/javascript">WebFontConfig={google:{families:[\'';
226
        foreach ($_fontsArray as $_font) {
227
            $_fontsOut .= $_font."','";
228
        }
229
        $_fontsOut = trim(trim($_fontsOut,"'"),",");
230
        $_fontsOut .= '] },classes:false, events:false, timeout:1500};(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>';
231
    }
232
 
233
    // inject in HTML
234
    $out = substr_replace($in, $_fontsOut."<link", strpos($in, "<link"), strlen("<link"));
0 ignored issues
show
Bug introduced by
The variable $_fontsOut does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
235
    return $out;
236
}
237
238
function autoptimize_extra_preconnectgooglefonts($in) {
239
    $autoptimize_extra_options = autoptimize_extra_get_options();
240
241
    // preconnect to fonts.gstatic.com speed up download of static font-files
242
    $in[] = "https://fonts.gstatic.com";
243
    if ( $autoptimize_extra_options['autoptimize_extra_radio_field_4'] == "4" ) {
244
        // and more preconnects for webfont.js
245
        $in[] = "https://ajax.googleapis.com/";
246
        $in[] = "https://fonts.googleapis.com";
247
    }
248
    return $in;
249
}
250
251
/* admin page functions */
252
function autoptimize_extra_admin() { 
253
    add_submenu_page( null, 'autoptimize_extra', 'autoptimize_extra', 'manage_options', 'autoptimize_extra', 'autoptimize_extra_options_page' );
254
    register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
255
}
256
257
function add_autoptimize_extra_tab($in) {
258
    $in=array_merge($in,array('autoptimize_extra' => 'Extra'));
259
    return $in;
260
}
261
262
function autoptimize_extra_options_page() { 
263
    $autoptimize_extra_options = autoptimize_extra_get_options();
264
    $_googlef = $autoptimize_extra_options['autoptimize_extra_radio_field_4'];
265
    ?>
266
    <style>
267
        #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
268
        #ao_settings_form .form-table th {font-weight: 100;}
269
        #autoptimize_extra_descr{font-size: 120%;}
270
    </style>
271
    <div class="wrap">
272
    <h1><?php _e('Autoptimize Settings','autoptimize'); ?></h1>
273
    <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
274
    <form id='ao_settings_form' action='options.php' method='post'>
275
        <?php settings_fields('autoptimize_extra_settings'); ?>
276
        <h2>Extra Auto-Optimizations</h2>
277
        <span id='autoptimize_extra_descr'>The following settings can improve your site's performance even more.</span>
278
        <table class="form-table">
279
            <tr>
280
                <th scope="row">Remove emojis</th>
281
                <td>
282
                    <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_1]' <?php checked( $autoptimize_extra_options['autoptimize_extra_checkbox_field_1'], 1 ); ?> value='1'>Removes WordPress' core emojis' inline CSS, inline JavaScript, and an otherwise un-autoptimized JavaScript file.</label>
283
                </td>
284
            </tr>
285
            <tr>
286
                <th scope="row">Remove query strings from static resources</th>
287
                <td>
288
                    <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_0]' <?php checked( $autoptimize_extra_options['autoptimize_extra_checkbox_field_0'], 1 ); ?> value='1'>Removing query strings (or more specificaly the <code>ver</code> parameter) will not improve load time, but might improve performance scores.</label>
289
                </td>
290
            </tr>
291
            <tr>
292
                <th scope="row">Google Fonts</th>
293
                <td>
294
                    <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="1" <?php if (!in_array($_googlef,array(2,3,4))) {echo "checked"; }  ?>>Leave as is<br/>
295
                    <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="2" <?php checked(2, $_googlef, true); ?> >Remove Google Fonts<br/>
296
                    <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="3" <?php checked(3, $_googlef, true); ?>>Combine and link in head<br/>
297
                    <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked(4, $_googlef, true); ?>>Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a><br/>
298
                </td>
299
            </tr>
300
            <tr>
301
                <th scope="row">Preconnect to 3rd party domains <em>(advanced users)</em></th>
302
                <td>
303
                    <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_2]' value='<?php echo $autoptimize_extra_options['autoptimize_extra_text_field_2']; ?>'><br />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).</label>
304
                </td>
305
            </tr>
306
            <tr>
307
                <th scope="row">Async Javascript-files <em>(advanced users)</em></th>
308
                <td>
309
                    <input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_3]' value='<?php echo $autoptimize_extra_options['autoptimize_extra_text_field_3']; ?>'>
310
                    <br />
311
                    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.
312
                </td>
313
            </tr>
314
        </table>
315
        <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Save Changes"  /></p>
316
    </form>
317
    <?php
318
}
319