autoptimizeBase::restore_noptimize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Base class other (more-specific) classes inherit from.
4
 */
5
6
if ( ! defined( 'ABSPATH' ) ) {
7
    exit;
8
}
9
10
abstract class autoptimizeBase
11
{
12
    /**
13
     * Holds content being processed (html, scripts, styles)
14
     *
15
     * @var string
16
     */
17
    protected $content = '';
18
19
    /**
20
     * Controls debug logging.
21
     *
22
     * @var bool
23
     */
24
    public $debug_log = false;
25
26
    /**
27
     * Initiated $cdn_url.
28
     *
29
     * @var string
30
     */
31
    public $cdn_url = '';
32
33
    public function __construct( $content )
34
    {
35
        $this->content = $content;
36
    }
37
38
    /**
39
     * Reads the page and collects tags.
40
     *
41
     * @param array $options Options.
42
     *
43
     * @return bool
44
     */
45
    abstract public function read( $options );
46
47
    /**
48
     * Joins and optimizes collected things.
49
     *
50
     * @return bool
51
     */
52
    abstract public function minify();
53
54
    /**
55
     * Caches the things.
56
     *
57
     * @return void
58
     */
59
    abstract public function cache();
60
61
    /**
62
     * Returns the content
63
     *
64
     * @return string
65
     */
66
    abstract public function getcontent();
67
68
    /**
69
     * Tranfsorms a given URL to a full local filepath if possible.
70
     * Returns local filepath or false.
71
     *
72
     * @param string $url URL to transform.
73
     *
74
     * @return bool|string
75
     */
76
    public function getpath( $url )
77
    {
78
        $url = apply_filters( 'autoptimize_filter_cssjs_alter_url', $url );
79
80
        if ( false !== strpos( $url, '%' ) ) {
81
            $url = urldecode( $url );
82
        }
83
84
        $site_host    = parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST );
85
        $content_host = parse_url( AUTOPTIMIZE_WP_ROOT_URL, PHP_URL_HOST );
86
87
        // Normalizing attempts...
88
        $double_slash_position = strpos( $url, '//' );
89
        if ( 0 === $double_slash_position ) {
90
            if ( is_ssl() ) {
91
                $url = 'https:' . $url;
92
            } else {
93
                $url = 'http:' . $url;
94
            }
95
        } elseif ( ( false === $double_slash_position ) && ( false === strpos( $url, $site_host ) ) ) {
96
            if ( AUTOPTIMIZE_WP_SITE_URL === $site_host ) {
97
                $url = AUTOPTIMIZE_WP_SITE_URL . $url;
98
            } else {
99
                $url = AUTOPTIMIZE_WP_SITE_URL . autoptimizeUtils::path_canonicalize( $url );
100
            }
101
        }
102
103
        if ( $site_host !== $content_host ) {
104
            $url = str_replace( AUTOPTIMIZE_WP_CONTENT_URL, AUTOPTIMIZE_WP_SITE_URL . AUTOPTIMIZE_WP_CONTENT_NAME, $url );
105
        }
106
107
        // First check; hostname wp site should be hostname of url!
108
        $url_host = @parse_url( $url, PHP_URL_HOST ); // @codingStandardsIgnoreLine
109
        if ( $url_host !== $site_host ) {
110
            /**
111
             * First try to get all domains from WPML (if available)
112
             * then explicitely declare $this->cdn_url as OK as well
113
             * then apply own filter autoptimize_filter_cssjs_multidomain takes an array of hostnames
114
             * each item in that array will be considered part of the same WP multisite installation
115
             */
116
            $multidomains = array();
117
118
            $multidomains_wpml = apply_filters( 'wpml_setting', array(), 'language_domains' );
119
            if ( ! empty( $multidomains_wpml ) ) {
120
                $multidomains = array_map( array( $this, 'get_url_hostname' ), $multidomains_wpml );
121
            }
122
123
            if ( ! empty( $this->cdn_url ) ) {
124
                $multidomains[] = parse_url( $this->cdn_url, PHP_URL_HOST );
125
            }
126
127
            $multidomains = apply_filters( 'autoptimize_filter_cssjs_multidomain', $multidomains );
128
129
            if ( ! empty( $multidomains ) ) {
130
                if ( in_array( $url_host, $multidomains ) ) {
131
                    $url = str_replace( $url_host, $site_host, $url );
132
                } else {
133
                    return false;
134
                }
135
            } else {
136
                return false;
137
            }
138
        }
139
140
        // Try to remove "wp root url" from url while not minding http<>https.
141
        $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_ROOT_URL );
142
143
        if ( $site_host !== $content_host ) {
144
            // As we replaced the content-domain with the site-domain, we should match against that.
145
            $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_SITE_URL );
146
        }
147
        
148
        if ( is_multisite() && ! is_main_site() && ! empty( $this->cdn_url ) ) {
149
            // multisite child sites with CDN need the network_site_url as tmp_ao_root but only if directory-based multisite.
150
            $_network_site_url = network_site_url();
151
            if ( strpos( AUTOPTIMIZE_WP_SITE_URL, $_network_site_url ) !== false ) {
152
                $tmp_ao_root = preg_replace( '/https?:/', '', $_network_site_url );
153
            }
154
        }
155
156
        $tmp_url = preg_replace( '/https?:/', '', $url );
157
        $path    = str_replace( $tmp_ao_root, '', $tmp_url );
158
159
        // If path starts with :// or //, this is not a URL in the WP context and
160
        // we have to assume we can't aggregate.
161
        if ( preg_match( '#^:?//#', $path ) ) {
162
            // External script/css (adsense, etc).
163
            return false;
164
        }
165
166
        // Prepend with WP_ROOT_DIR to have full path to file.
167
        $path = str_replace( '//', '/', trailingslashit( WP_ROOT_DIR ) . $path );
168
169
        // Final check: does file exist and is it readable?
170
        if ( file_exists( $path ) && is_file( $path ) && is_readable( $path ) ) {
171
            return $path;
172
        } else {
173
            return false;
174
        }
175
    }
176
177
    /**
178
     * Returns the hostname part of a given $url if we're able to parse it.
179
     * If not, it returns the original url (prefixed with http:// scheme in case
180
     * it was missing).
181
     * Used as callback for WPML multidomains filter.
182
     *
183
     * @param string $url URL.
184
     *
185
     * @return string
186
     */
187
    protected function get_url_hostname( $url )
188
    {
189
        // Checking that the url starts with something vaguely resembling a protocol.
190
        if ( ( 0 !== strpos( $url, 'http' ) ) && ( 0 !== strpos( $url, '//' ) ) ) {
191
            $url = 'http://' . $url;
192
        }
193
194
        // Grab the hostname.
195
        $hostname = parse_url( $url, PHP_URL_HOST );
196
197
        // Fallback when parse_url() fails.
198
        if ( empty( $hostname ) ) {
199
            $hostname = $url;
200
        }
201
202
        return $hostname;
203
    }
204
205
    /**
206
     * Hides everything between noptimize-comment tags.
207
     *
208
     * @param string $markup Markup to process.
209
     *
210
     * @return string
211
     */
212
    protected function hide_noptimize( $markup )
213
    {
214
        return $this->replace_contents_with_marker_if_exists(
215
            'NOPTIMIZE',
216
            '/<!--\s?noptimize\s?-->/',
217
            '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
218
            $markup
219
        );
220
    }
221
222
    /**
223
     * Unhide noptimize-tags.
224
     *
225
     * @param string $markup Markup to process.
226
     *
227
     * @return string
228
     */
229
    protected function restore_noptimize( $markup )
230
    {
231
        return $this->restore_marked_content( 'NOPTIMIZE', $markup );
232
    }
233
234
    /**
235
     * Hides "iehacks" content.
236
     *
237
     * @param string $markup Markup to process.
238
     *
239
     * @return string
240
     */
241
    protected function hide_iehacks( $markup )
242
    {
243
        return $this->replace_contents_with_marker_if_exists(
244
            'IEHACK', // Marker name...
245
            '<!--[if', // Invalid regex, will fallback to search using strpos()...
246
            '#<!--\[if.*?\[endif\]-->#is', // Replacement regex...
247
            $markup
248
        );
249
    }
250
251
    /**
252
     * Restores "hidden" iehacks content.
253
     *
254
     * @param string $markup Markup to process.
255
     *
256
     * @return string
257
     */
258
    protected function restore_iehacks( $markup )
259
    {
260
        return $this->restore_marked_content( 'IEHACK', $markup );
261
    }
262
263
    /**
264
     * "Hides" content within HTML comments using a regex-based replacement
265
     * if HTML comment markers are found.
266
     * `<!--example-->` becomes `%%COMMENTS%%ZXhhbXBsZQ==%%COMMENTS%%`
267
     *
268
     * @param string $markup Markup to process.
269
     *
270
     * @return string
271
     */
272
    protected function hide_comments( $markup )
273
    {
274
        return $this->replace_contents_with_marker_if_exists(
275
            'COMMENTS',
276
            '<!--',
277
            '#<!--.*?-->#is',
278
            $markup
279
        );
280
    }
281
282
    /**
283
     * Restores original HTML comment markers inside a string whose HTML
284
     * comments have been "hidden" by using `hide_comments()`.
285
     *
286
     * @param string $markup Markup to process.
287
     *
288
     * @return string
289
     */
290
    protected function restore_comments( $markup )
291
    {
292
        return $this->restore_marked_content( 'COMMENTS', $markup );
293
    }
294
295
    /**
296
     * Replaces the given URL with the CDN-version of it when CDN replacement
297
     * is supposed to be done.
298
     *
299
     * @param string $url URL to process.
300
     *
301
     * @return string
302
     */
303
    public function url_replace_cdn( $url )
304
    {
305
        // For 2.3 back-compat in which cdn-ing appeared to be automatically
306
        // including WP subfolder/subdirectory into account as part of cdn-ing,
307
        // even though it might've caused serious troubles in certain edge-cases.
308
        $cdn_url = autoptimizeUtils::tweak_cdn_url_if_needed( $this->cdn_url );
309
310
        // Allows API/filter to further tweak the cdn url...
311
        $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url );
312
        if ( ! empty( $cdn_url ) ) {
313
            $this->debug_log( 'before=' . $url );
314
315
            // Simple str_replace-based approach fails when $url is protocol-or-host-relative.
316
            $is_protocol_relative = autoptimizeUtils::is_protocol_relative( $url );
317
            $is_host_relative     = ( ! $is_protocol_relative && ( '/' === $url[0] ) );
318
            $cdn_url              = rtrim( $cdn_url, '/' );
319
320
            if ( $is_host_relative ) {
321
                // Prepending host-relative urls with the cdn url.
322
                $url = $cdn_url . $url;
323
            } else {
324
                // Either a protocol-relative or "regular" url, replacing it either way.
325
                if ( $is_protocol_relative ) {
326
                    // Massage $site_url so that simple str_replace() still "works" by
327
                    // searching for the protocol-relative version of AUTOPTIMIZE_WP_SITE_URL.
328
                    $site_url = str_replace( array( 'http:', 'https:' ), '', AUTOPTIMIZE_WP_SITE_URL );
329
                } else {
330
                    $site_url = AUTOPTIMIZE_WP_SITE_URL;
331
                }
332
                $this->debug_log( '`' . $site_url . '` -> `' . $cdn_url . '` in `' . $url . '`' );
333
                $url = str_replace( $site_url, $cdn_url, $url );
334
            }
335
336
            $this->debug_log( 'after=' . $url );
337
        }
338
339
        // Allow API filter to take further care of CDN replacement.
340
        $url = apply_filters( 'autoptimize_filter_base_replace_cdn', $url );
341
342
        return $url;
343
    }
344
345
    /**
346
     * Injects/replaces the given payload markup into `$this->content`
347
     * at the specified location.
348
     * If the specified tag cannot be found, the payload is appended into
349
     * $this->content along with a warning wrapped inside <!--noptimize--> tags.
350
     *
351
     * @param string $payload Markup to inject.
352
     * @param array  $where   Array specifying the tag name and method of injection.
353
     *                        Index 0 is the tag name (i.e., `</body>`).
354
     *                        Index 1 specifies ˛'before', 'after' or 'replace'. Defaults to 'before'.
355
     *
356
     * @return void
357
     */
358
    protected function inject_in_html( $payload, $where )
359
    {
360
        $warned   = false;
361
        $position = autoptimizeUtils::strpos( $this->content, $where[0] );
362
        if ( false !== $position ) {
363
            // Found the tag, setup content/injection as specified.
364
            if ( 'after' === $where[1] ) {
365
                $content = $where[0] . $payload;
366
            } elseif ( 'replace' === $where[1] ) {
367
                $content = $payload;
368
            } else {
369
                $content = $payload . $where[0];
370
            }
371
            // Place where specified.
372
            $this->content = autoptimizeUtils::substr_replace(
373
                $this->content,
374
                $content,
375
                $position,
376
                // Using plain strlen() should be safe here for now, since
377
                // we're not searching for multibyte chars here still...
378
                strlen( $where[0] )
379
            );
380
        } else {
381
            // Couldn't find what was specified, just append and add a warning.
382
            $this->content .= $payload;
383
            if ( ! $warned ) {
384
                $tag_display    = str_replace( array( '<', '>' ), '', $where[0] );
385
                $this->content .= '<!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `' . $tag_display . '` missing --><!--/noptimize-->';
386
                $warned         = true;
0 ignored issues
show
Unused Code introduced by
$warned is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
387
            }
388
        }
389
    }
390
391
    /**
392
     * Returns true if given `$tag` is found in the list of `$removables`.
393
     *
394
     * @param string $tag Tag to search for.
395
     * @param array  $removables List of things considered completely removable.
396
     *
397
     * @return bool
398
     */
399
    protected function isremovable( $tag, $removables )
400
    {
401
        foreach ( $removables as $match ) {
402
            if ( false !== strpos( $tag, $match ) ) {
403
                return true;
404
            }
405
        }
406
407
        return false;
408
    }
409
410
    /**
411
     * Callback used in `self::inject_minified()`.
412
     *
413
     * @param array $matches Regex matches.
414
     *
415
     * @return string
416
     */
417
    public function inject_minified_callback( $matches )
418
    {
419
        static $conf = null;
420
        if ( null === $conf ) {
421
            $conf = autoptimizeConfig::instance();
422
        }
423
424
        /**
425
         * $matches[1] holds the whole match caught by regex in self::inject_minified(),
426
         * so we take that and split the string on `|`.
427
         * First element is the filepath, second is the md5 hash of contents
428
         * the filepath had when it was being processed.
429
         * If we don't have those, we'll bail out early.
430
        */
431
        $filepath = null;
432
        $filehash = null;
433
434
        // Grab the parts we need.
435
        $parts = explode( '|', $matches[1] );
436
        if ( ! empty( $parts ) ) {
437
            $filepath = isset( $parts[0] ) ? base64_decode( $parts[0] ) : null;
438
            $filehash = isset( $parts[1] ) ? $parts[1] : null;
439
        }
440
441
        // Bail early if something's not right...
442
        if ( ! $filepath || ! $filehash ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filepath of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
443
            return "\n";
444
        }
445
446
        $filecontent = file_get_contents( $filepath );
447
448
        // Some things are differently handled for css/js...
449
        $is_js_file = ( '.js' === substr( $filepath, -3, 3 ) );
450
451
        $is_css_file = false;
452
        if ( ! $is_js_file ) {
453
            $is_css_file = ( '.css' === substr( $filepath, -4, 4 ) );
454
        }
455
456
        // BOMs being nuked here unconditionally (regardless of where they are)!
457
        $filecontent = preg_replace( "#\x{EF}\x{BB}\x{BF}#", '', $filecontent );
458
459
        // Remove comments and blank lines.
460
        if ( $is_js_file ) {
461
            $filecontent = preg_replace( '#^\s*\/\/.*$#Um', '', $filecontent );
462
        }
463
464
        // Nuke un-important comments.
465
        $filecontent = preg_replace( '#^\s*\/\*[^!].*\*\/\s?#Um', '', $filecontent );
466
467
        // Normalize newlines.
468
        $filecontent = preg_replace( '#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#', "\n", $filecontent );
469
470
        // JS specifics.
471
        if ( $is_js_file ) {
472
            // Append a semicolon at the end of js files if it's missing.
473
            $last_char = substr( $filecontent, -1, 1 );
474
            if ( ';' !== $last_char && '}' !== $last_char ) {
475
                $filecontent .= ';';
476
            }
477
            // Check if try/catch should be used.
478
            $opt_js_try_catch = $conf->get( 'autoptimize_js_trycatch' );
479
            if ( 'on' === $opt_js_try_catch ) {
480
                // It should, wrap in try/catch.
481
                $filecontent = 'try{' . $filecontent . '}catch(e){}';
482
            }
483
        } elseif ( $is_css_file ) {
484
            $filecontent = autoptimizeStyles::fixurls( $filepath, $filecontent );
485
        } else {
486
            $filecontent = '';
487
        }
488
489
        // Return modified (or empty!) code/content.
490
        return "\n" . $filecontent;
491
    }
492
493
    /**
494
     * Inject already minified code in optimized JS/CSS.
495
     *
496
     * @param string $in Markup.
497
     *
498
     * @return string
499
     */
500
    protected function inject_minified( $in )
501
    {
502
        $out = $in;
503
        if ( false !== strpos( $in, '%%INJECTLATER%%' ) ) {
504
            $out = preg_replace_callback(
505
                '#\/\*\!%%INJECTLATER' . AUTOPTIMIZE_HASH . '%%(.*?)%%INJECTLATER%%\*\/#is',
506
                array( $this, 'inject_minified_callback' ),
507
                $in
508
            );
509
        }
510
511
        return $out;
512
    }
513
514
    /**
515
     * Specialized method to create the INJECTLATER marker.
516
     * These are somewhat "special", in the sense that they're additionally wrapped
517
     * within an "exclamation mark style" comment, so that they're not stripped
518
     * out by minifiers.
519
     * They also currently contain the hash of the file's contents too (unlike other markers).
520
     *
521
     * @param string $filepath Filepath.
522
     * @param string $hash Hash.
523
     *
524
     * @return string
525
     */
526
    public static function build_injectlater_marker( $filepath, $hash )
527
    {
528
        $contents = '/*!' . self::build_marker( 'INJECTLATER', $filepath, $hash ) . '*/';
529
530
        return $contents;
531
    }
532
533
    /**
534
     * Creates and returns a `%%`-style named marker which holds
535
     * the base64 encoded `$data`.
536
     * If `$hash` is provided, it's appended to the base64 encoded string
537
     * using `|` as the separator (in order to support building the
538
     * somewhat special/different INJECTLATER marker).
539
     *
540
     * @param string      $name Marker name.
541
     * @param string      $data Marker data which will be base64-encoded.
542
     * @param string|null $hash Optional.
543
     *
544
     * @return string
545
     */
546
    public static function build_marker( $name, $data, $hash = null )
547
    {
548
        // Start the marker, add the data.
549
        $marker = '%%' . $name . AUTOPTIMIZE_HASH . '%%' . base64_encode( $data );
550
551
        // Add the hash if provided.
552
        if ( null !== $hash ) {
553
            $marker .= '|' . $hash;
554
        }
555
556
        // Close the marker.
557
        $marker .= '%%' . $name . '%%';
558
559
        return $marker;
560
    }
561
562
    /**
563
     * Searches for `$search` in `$content` (using either `preg_match()`
564
     * or `strpos()`, depending on whether `$search` is a valid regex pattern or not).
565
     * If something is found, it replaces `$content` using `$re_replace_pattern`,
566
     * effectively creating our named markers (`%%{$marker}%%`.
567
     * These are then at some point replaced back to their actual/original/modified
568
     * contents using `autoptimizeBase::restore_marked_content()`.
569
     *
570
     * @param string $marker Marker name (without percent characters).
571
     * @param string $search A string or full blown regex pattern to search for in $content. Uses `strpos()` or `preg_match()`.
572
     * @param string $re_replace_pattern Regex pattern to use when replacing contents.
573
     * @param string $content Content to work on.
574
     *
575
     * @return string
576
     */
577
    public static function replace_contents_with_marker_if_exists( $marker, $search, $re_replace_pattern, $content )
578
    {
579
        $found = false;
0 ignored issues
show
Unused Code introduced by
$found is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
580
581
        $is_regex = autoptimizeUtils::str_is_valid_regex( $search );
582
        if ( $is_regex ) {
583
            $found = preg_match( $search, $content );
584
        } else {
585
            $found = ( false !== strpos( $content, $search ) );
586
        }
587
588
        if ( $found ) {
589
            $content = preg_replace_callback(
590
                $re_replace_pattern,
591
                function( $matches ) use ( $marker ) {
592
                    return autoptimizeBase::build_marker( $marker, $matches[0] );
593
                },
594
                $content
595
            );
596
        }
597
598
        return $content;
599
    }
600
601
    /**
602
     * Complements `autoptimizeBase::replace_contents_with_marker_if_exists()`.
603
     *
604
     * @param string $marker Marker.
605
     * @param string $content Markup.
606
     *
607
     * @return string
608
     */
609
    public static function restore_marked_content( $marker, $content )
610
    {
611
        if ( false !== strpos( $content, $marker ) ) {
612
            $content = preg_replace_callback(
613
                '#%%' . $marker . AUTOPTIMIZE_HASH . '%%(.*?)%%' . $marker . '%%#is',
614
                function ( $matches ) {
615
                    return base64_decode( $matches[1] );
616
                },
617
                $content
618
            );
619
        }
620
621
        return $content;
622
    }
623
624
    /**
625
     * Logs given `$data` for debugging purposes (when debug logging is on).
626
     *
627
     * @param mixed $data Data to log.
628
     *
629
     * @return void
630
     */
631
    protected function debug_log( $data )
632
    {
633
        if ( ! isset( $this->debug_log ) || ! $this->debug_log ) {
634
            return;
635
        }
636
637
        if ( ! is_string( $data ) && ! is_resource( $data ) ) {
638
            $data = var_export( $data, true );
639
        }
640
641
        error_log( $data );
642
    }
643
644
    /**
645
     * Checks if a single local css/js file can be minified and returns source if so.
646
     *
647
     * @param string $filepath Filepath.
648
     *
649
     * @return bool|string to be minified code or false.
650
     */
651
    protected function prepare_minify_single( $filepath )
652
    {
653
        // Decide what we're dealing with, return false if we don't know.
654
        if ( autoptimizeUtils::str_ends_in( $filepath, '.js' ) ) {
655
            $type = 'js';
656
        } elseif ( autoptimizeUtils::str_ends_in( $filepath, '.css' ) ) {
657
            $type = 'css';
658
        } else {
659
            return false;
660
        }
661
662
        // Bail if it looks like its already minifed (by having -min or .min
663
        // in filename) or if it looks like WP jquery.js (which is minified).
664
        $minified_variants = array(
665
            '-min.' . $type,
666
            '.min.' . $type,
667
            'js/jquery/jquery.js',
668
        );
669
        foreach ( $minified_variants as $ending ) {
670
            if ( autoptimizeUtils::str_ends_in( $filepath, $ending ) ) {
671
                return false;
672
            }
673
        }
674
675
        // Get file contents, bail if empty.
676
        $contents = file_get_contents( $filepath );
677
678
        return $contents;
679
    }
680
681
    /**
682
     * Given an autoptimizeCache instance returns the (maybe cdn-ed) url of
683
     * the cached file.
684
     *
685
     * @param autoptimizeCache $cache autoptimizeCache instance.
686
     *
687
     * @return string
688
     */
689
    protected function build_minify_single_url( autoptimizeCache $cache )
690
    {
691
        $url = AUTOPTIMIZE_CACHE_URL . $cache->getname();
692
693
        // CDN-replace the resulting URL if needed...
694
        $url = $this->url_replace_cdn( $url );
695
696
        return $url;
697
    }
698
}
699