This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Handles optimizing images. |
||
4 | */ |
||
5 | |||
6 | if ( ! defined( 'ABSPATH' ) ) { |
||
7 | exit; |
||
8 | } |
||
9 | |||
10 | class autoptimizeImages |
||
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 | public function __construct( array $options = array() ) |
||
27 | { |
||
28 | // If options are not provided, fetch them. |
||
29 | if ( empty( $options ) ) { |
||
30 | $options = $this->fetch_options(); |
||
31 | } |
||
32 | |||
33 | $this->set_options( $options ); |
||
34 | $this->lazyload_counter = 0; |
||
0 ignored issues
–
show
|
|||
35 | } |
||
36 | |||
37 | public function set_options( array $options ) |
||
38 | { |
||
39 | $this->options = $options; |
||
40 | |||
41 | return $this; |
||
42 | } |
||
43 | |||
44 | public static function fetch_options() |
||
45 | { |
||
46 | $value = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings' ); |
||
47 | if ( empty( $value ) ) { |
||
48 | // Fallback to returning defaults when no stored option exists yet. |
||
49 | $value = autoptimizeConfig::get_ao_imgopt_default_options(); |
||
50 | } |
||
51 | |||
52 | // get service availability and add it to the options-array. |
||
53 | $value['availabilities'] = autoptimizeOptionWrapper::get_option( 'autoptimize_service_availablity' ); |
||
54 | |||
55 | if ( empty( $value['availabilities'] ) ) { |
||
56 | $value['availabilities'] = autoptimizeUtils::check_service_availability( true ); |
||
0 ignored issues
–
show
true is of type boolean , but the function expects a false|string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
57 | } |
||
58 | |||
59 | return $value; |
||
60 | } |
||
61 | |||
62 | public static function imgopt_active() |
||
63 | { |
||
64 | // function to quickly check if imgopt is active, used below but also in |
||
65 | // autoptimizeMain.php to start ob_ even if no HTML, JS or CSS optimizing is done |
||
66 | // and does not use/ request the availablity data (which could slow things down). |
||
67 | static $imgopt_active = null; |
||
68 | |||
69 | if ( null === $imgopt_active ) { |
||
70 | $opts = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings', '' ); |
||
71 | 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'] ) { |
||
72 | $imgopt_active = true; |
||
73 | } else { |
||
74 | $imgopt_active = false; |
||
75 | } |
||
76 | } |
||
77 | |||
78 | return $imgopt_active; |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Helper for getting a singleton instance. While being an |
||
83 | * anti-pattern generally, it comes in handy for now from a |
||
84 | * readability/maintainability perspective, until we get some |
||
85 | * proper dependency injection going. |
||
86 | * |
||
87 | * @return self |
||
88 | */ |
||
89 | public static function instance() |
||
90 | { |
||
91 | if ( null === self::$instance ) { |
||
92 | self::$instance = new self(); |
||
93 | } |
||
94 | |||
95 | return self::$instance; |
||
96 | } |
||
97 | |||
98 | View Code Duplication | public function run() |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
99 | { |
||
100 | if ( is_admin() ) { |
||
101 | if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) { |
||
102 | add_action( 'network_admin_menu', array( $this, 'imgopt_admin_menu' ) ); |
||
103 | } else { |
||
104 | add_action( 'admin_menu', array( $this, 'imgopt_admin_menu' ) ); |
||
105 | } |
||
106 | add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_imgopt_tab' ), 9 ); |
||
107 | } else { |
||
108 | add_action( 'wp', array( $this, 'run_on_frontend' ) ); |
||
109 | } |
||
110 | } |
||
111 | |||
112 | public function run_on_frontend() { |
||
113 | if ( ! $this->should_run() ) { |
||
114 | if ( $this->should_lazyload() ) { |
||
115 | add_filter( |
||
116 | 'wp_lazy_loading_enabled', |
||
117 | '__return_false' |
||
118 | ); |
||
119 | add_filter( |
||
120 | 'autoptimize_html_after_minify', |
||
121 | array( $this, 'filter_lazyload_images' ), |
||
122 | 10, |
||
123 | 1 |
||
124 | ); |
||
125 | add_action( |
||
126 | 'wp_footer', |
||
127 | array( $this, 'add_lazyload_js_footer' ), |
||
128 | 10, |
||
129 | 0 |
||
130 | ); |
||
131 | } |
||
132 | return; |
||
133 | } |
||
134 | |||
135 | $active = false; |
||
136 | |||
137 | if ( apply_filters( 'autoptimize_filter_imgopt_do', true ) ) { |
||
138 | add_filter( |
||
139 | 'autoptimize_html_after_minify', |
||
140 | array( $this, 'filter_optimize_images' ), |
||
141 | 10, |
||
142 | 1 |
||
143 | ); |
||
144 | $active = true; |
||
145 | } |
||
146 | |||
147 | if ( apply_filters( 'autoptimize_filter_imgopt_do_css', true ) ) { |
||
148 | add_filter( |
||
149 | 'autoptimize_filter_base_replace_cdn', |
||
150 | array( $this, 'filter_optimize_css_images' ), |
||
151 | 10, |
||
152 | 1 |
||
153 | ); |
||
154 | $active = true; |
||
155 | } |
||
156 | |||
157 | if ( $active ) { |
||
158 | add_filter( |
||
159 | 'autoptimize_extra_filter_tobepreconn', |
||
160 | array( $this, 'filter_preconnect_imgopt_url' ), |
||
161 | 10, |
||
162 | 1 |
||
163 | ); |
||
164 | } |
||
165 | |||
166 | if ( $this->should_lazyload() ) { |
||
167 | add_filter( |
||
168 | 'wp_lazy_loading_enabled', |
||
169 | '__return_false' |
||
170 | ); |
||
171 | add_action( |
||
172 | 'wp_footer', |
||
173 | array( $this, 'add_lazyload_js_footer' ), |
||
174 | 10, |
||
175 | 0 |
||
176 | ); |
||
177 | } |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Basic checks before we can run. |
||
182 | * |
||
183 | * @return bool |
||
184 | */ |
||
185 | protected function should_run() |
||
186 | { |
||
187 | $opts = $this->options; |
||
188 | $service_not_down = ( 'down' !== $opts['availabilities']['extra_imgopt']['status'] ); |
||
189 | $not_launch_status = ( 'launch' !== $opts['availabilities']['extra_imgopt']['status'] ); |
||
190 | |||
191 | $do_cdn = true; |
||
192 | $_userstatus = $this->get_imgopt_provider_userstatus(); |
||
193 | if ( isset( $_userstatus['Status'] ) && ( -2 == $_userstatus['Status'] || -3 == $_userstatus['Status'] ) ) { |
||
194 | // don't even attempt to put images on CDN if heavily exceeded threshold or if site not reachable. |
||
195 | $do_cdn = false; |
||
196 | } |
||
197 | |||
198 | if ( |
||
199 | $this->imgopt_active() |
||
200 | && $do_cdn |
||
201 | && $service_not_down |
||
202 | && ( $not_launch_status || $this->launch_ok() ) |
||
203 | ) { |
||
204 | return true; |
||
205 | } |
||
206 | return false; |
||
207 | } |
||
208 | |||
209 | public function get_imgopt_host() |
||
210 | { |
||
211 | static $imgopt_host = null; |
||
212 | |||
213 | if ( null === $imgopt_host ) { |
||
214 | $imgopt_host = 'https://cdn.shortpixel.ai/'; |
||
215 | $avail_imgopt = $this->options['availabilities']['extra_imgopt']; |
||
216 | if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) { |
||
217 | $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) ); |
||
218 | } |
||
219 | $imgopt_host = apply_filters( 'autoptimize_filter_imgopt_host', $imgopt_host ); |
||
220 | } |
||
221 | |||
222 | return $imgopt_host; |
||
223 | } |
||
224 | |||
225 | public static function get_imgopt_host_wrapper() |
||
226 | { |
||
227 | // needed for CI tests. |
||
228 | $self = new self(); |
||
229 | return $self->get_imgopt_host(); |
||
230 | } |
||
231 | |||
232 | public static function get_service_url_suffix() |
||
233 | { |
||
234 | $suffix = '/af/SPZURYE109483/' . AUTOPTIMIZE_SITE_DOMAIN; |
||
235 | |||
236 | return $suffix; |
||
237 | } |
||
238 | |||
239 | public function get_img_quality_string() |
||
240 | { |
||
241 | static $quality = null; |
||
242 | |||
243 | if ( null === $quality ) { |
||
244 | $q_array = $this->get_img_quality_array(); |
||
245 | $setting = $this->get_img_quality_setting(); |
||
246 | $quality = apply_filters( |
||
247 | 'autoptimize_filter_imgopt_quality', |
||
248 | 'q_' . $q_array[ $setting ] |
||
249 | ); |
||
250 | } |
||
251 | |||
252 | return $quality; |
||
253 | } |
||
254 | |||
255 | public function get_img_quality_array() |
||
256 | { |
||
257 | static $map = null; |
||
258 | |||
259 | if ( null === $map ) { |
||
260 | $map = array( |
||
261 | '1' => 'lossy', |
||
262 | '2' => 'glossy', |
||
263 | '3' => 'lossless', |
||
264 | ); |
||
265 | $map = apply_filters( |
||
266 | 'autoptimize_filter_imgopt_quality_array', |
||
267 | $map |
||
268 | ); |
||
269 | } |
||
270 | |||
271 | return $map; |
||
272 | } |
||
273 | |||
274 | public function get_img_quality_setting() |
||
275 | { |
||
276 | static $q = null; |
||
277 | |||
278 | if ( null === $q ) { |
||
279 | if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_select_field_2', $this->options ) ) { |
||
280 | $setting = $this->options['autoptimize_imgopt_select_field_2']; |
||
281 | } |
||
282 | |||
283 | if ( ! isset( $setting ) || empty( $setting ) || ( '1' !== $setting && '3' !== $setting ) ) { |
||
284 | // default image opt. value is 2 ("glossy"). |
||
285 | $q = '2'; |
||
286 | } else { |
||
287 | $q = $setting; |
||
288 | } |
||
289 | } |
||
290 | |||
291 | return $q; |
||
292 | } |
||
293 | |||
294 | public function filter_preconnect_imgopt_url( array $in ) |
||
295 | { |
||
296 | $url_parts = parse_url( $this->get_imgopt_base_url() ); |
||
297 | $in[] = $url_parts['scheme'] . '://' . $url_parts['host']; |
||
298 | |||
299 | return $in; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Makes sure given url contains the full scheme and hostname |
||
304 | * in case they're not present already. |
||
305 | * |
||
306 | * @param string $in Image url to normalize. |
||
307 | * |
||
308 | * @return string |
||
309 | */ |
||
310 | private function normalize_img_url( $in ) |
||
311 | { |
||
312 | // Only parse the site url once. |
||
313 | static $parsed_site_url = null; |
||
314 | if ( null === $parsed_site_url ) { |
||
315 | $parsed_site_url = parse_url( site_url() ); |
||
316 | } |
||
317 | |||
318 | // get CDN domain once. |
||
319 | static $cdn_domain = null; |
||
320 | if ( is_null( $cdn_domain ) ) { |
||
321 | $cdn_url = $this->get_cdn_url(); |
||
322 | if ( ! empty( $cdn_url ) ) { |
||
323 | $cdn_domain = parse_url( $cdn_url, PHP_URL_HOST ); |
||
324 | } else { |
||
325 | $cdn_domain = ''; |
||
326 | } |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * This method gets called a lot, often for identical urls it seems. |
||
331 | * `filter_optimize_css_images()` calls us, uses the resulting url and |
||
332 | * gives it to `can_optimize_image()`, and if that returns trueish |
||
333 | * then `build_imgopt_url()` is called (which, again, calls this method). |
||
334 | * Until we dig deeper into whether this all must really happen that |
||
335 | * way, having an internal cache here helps (to avoid doing repeated |
||
336 | * identical string operations). |
||
337 | */ |
||
338 | static $cache = null; |
||
339 | if ( null === $cache ) { |
||
340 | $cache = array(); |
||
341 | } |
||
342 | |||
343 | // Do the work on cache miss only. |
||
344 | if ( ! isset( $cache[ $in ] ) ) { |
||
345 | // Default to (the trimmed version of) what was given to us. |
||
346 | $result = trim( $in ); |
||
347 | |||
348 | // Some silly plugins wrap background images in html-encoded quotes, so remove those from the img url. |
||
349 | $result = $this->fix_silly_bgimg_quotes( $result ); |
||
350 | |||
351 | if ( autoptimizeUtils::is_protocol_relative( $result ) ) { |
||
352 | $result = $parsed_site_url['scheme'] . ':' . $result; |
||
353 | } elseif ( 0 === strpos( $result, '/' ) ) { |
||
354 | // Root-relative... |
||
355 | $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result; |
||
356 | } elseif ( ! empty( $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) { |
||
357 | $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result ); |
||
358 | } |
||
359 | |||
360 | // filter (default off) to remove QS from image URL's to avoid eating away optimization credits. |
||
361 | if ( apply_filters( 'autoptimize_filter_imgopt_no_querystring', false ) && strpos( $result, '?' ) !== false ) { |
||
362 | $result = strtok( $result, '?' ); |
||
363 | } |
||
364 | |||
365 | $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result ); |
||
366 | |||
367 | // Store in cache. |
||
368 | $cache[ $in ] = $result; |
||
369 | } |
||
370 | |||
371 | return $cache[ $in ]; |
||
372 | } |
||
373 | |||
374 | public function filter_optimize_css_images( $in ) |
||
375 | { |
||
376 | $in = $this->normalize_img_url( $in ); |
||
377 | |||
378 | if ( $this->can_optimize_image( $in ) ) { |
||
379 | return $this->build_imgopt_url( $in, '', '' ); |
||
380 | } else { |
||
381 | return $in; |
||
382 | } |
||
383 | } |
||
384 | |||
385 | private function get_imgopt_base_url() |
||
386 | { |
||
387 | static $imgopt_base_url = null; |
||
388 | |||
389 | if ( null === $imgopt_base_url ) { |
||
390 | $imgopt_host = $this->get_imgopt_host(); |
||
391 | $quality = $this->get_img_quality_string(); |
||
392 | $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank. |
||
393 | $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val; |
||
394 | $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url ); |
||
395 | } |
||
396 | |||
397 | return $imgopt_base_url; |
||
398 | } |
||
399 | |||
400 | private function can_optimize_image( $url, $tag = '', $testing = false ) |
||
401 | { |
||
402 | static $cdn_url = null; |
||
403 | static $nopti_images = null; |
||
404 | |||
405 | if ( null === $cdn_url ) { |
||
406 | $cdn_url = apply_filters( |
||
407 | 'autoptimize_filter_base_cdnurl', |
||
408 | autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' ) |
||
409 | ); |
||
410 | } |
||
411 | |||
412 | if ( null === $nopti_images || $testing ) { |
||
413 | if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) { |
||
414 | $nopti_images = $this->options['autoptimize_imgopt_text_field_6']; |
||
415 | } |
||
416 | $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images ); |
||
417 | } |
||
418 | |||
419 | $site_host = AUTOPTIMIZE_SITE_DOMAIN; |
||
420 | $url = $this->normalize_img_url( $url ); |
||
421 | $url_parsed = parse_url( $url ); |
||
422 | |||
423 | if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) { |
||
424 | return false; |
||
425 | } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) { |
||
426 | return false; |
||
427 | } elseif ( strpos( $url, '.php' ) !== false ) { |
||
428 | return false; |
||
429 | } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp', '.avif' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) { |
||
430 | // fixme: better check against end of string. |
||
431 | return false; |
||
432 | } elseif ( ! empty( $nopti_images ) ) { |
||
433 | $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) ); |
||
434 | foreach ( $nopti_images_array as $nopti_image ) { |
||
435 | if ( strpos( $url, $nopti_image ) !== false || ( ( '' !== $tag && strpos( $tag, $nopti_image ) !== false ) ) ) { |
||
436 | return false; |
||
437 | } |
||
438 | } |
||
439 | } |
||
440 | return true; |
||
441 | } |
||
442 | |||
443 | private function build_imgopt_url( $orig_url, $width = 0, $height = 0 ) |
||
444 | { |
||
445 | // sanitize width and height. |
||
446 | if ( strpos( $width, '%' ) !== false ) { |
||
447 | $width = 0; |
||
448 | } |
||
449 | if ( strpos( $height, '%' ) !== false ) { |
||
450 | $height = 0; |
||
451 | } |
||
452 | $width = (int) $width; |
||
453 | $height = (int) $height; |
||
454 | |||
455 | $filtered_url = apply_filters( |
||
456 | 'autoptimize_filter_imgopt_build_url', |
||
457 | $orig_url, |
||
458 | $width, |
||
459 | $height |
||
460 | ); |
||
461 | |||
462 | // If filter modified the url, return that. |
||
463 | if ( $filtered_url !== $orig_url ) { |
||
464 | return $filtered_url; |
||
465 | } |
||
466 | |||
467 | $normalized_url = $this->normalize_img_url( $orig_url ); |
||
468 | |||
469 | // 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. |
||
470 | if ( apply_filters( 'autoptimize_filter_imgopt_check_normalized_url', true ) && ! preg_match( '/[^\x20-\x7e]/', $normalized_url ) && false === filter_var( $normalized_url, FILTER_VALIDATE_URL ) ) { |
||
471 | return $orig_url; |
||
472 | } |
||
473 | |||
474 | $imgopt_base_url = $this->get_imgopt_base_url(); |
||
475 | $imgopt_size = ''; |
||
476 | |||
477 | if ( $width && 0 !== $width ) { |
||
478 | $imgopt_size = ',w_' . $width; |
||
479 | } |
||
480 | |||
481 | if ( $height && 0 !== $height ) { |
||
482 | $imgopt_size .= ',h_' . $height; |
||
483 | } |
||
484 | |||
485 | $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url; |
||
486 | |||
487 | return $url; |
||
488 | } |
||
489 | |||
490 | public function replace_data_thumbs( $matches ) |
||
491 | { |
||
492 | return $this->replace_img_callback( $matches, 150, 150 ); |
||
493 | } |
||
494 | |||
495 | public function replace_img_callback( $matches, $width = 0, $height = 0 ) |
||
496 | { |
||
497 | $_normalized_img_url = $this->normalize_img_url( $matches[1] ); |
||
498 | if ( $this->can_optimize_image( $matches[1], $matches[0] ) ) { |
||
499 | return str_replace( $matches[1], $this->build_imgopt_url( $_normalized_img_url, $width, $height ), $matches[0] ); |
||
500 | } else { |
||
501 | return $matches[0]; |
||
502 | } |
||
503 | } |
||
504 | |||
505 | public function replace_icon_callback( $matches ) |
||
506 | { |
||
507 | if ( array_key_exists( '2', $matches ) ) { |
||
508 | $sizes = explode( 'x', $matches[2] ); |
||
509 | $width = $sizes[0]; |
||
510 | $height = $sizes[1]; |
||
511 | } else { |
||
512 | $width = 180; |
||
513 | $height = 180; |
||
514 | } |
||
515 | |||
516 | // make sure we're not trying to optimize a *.ico file |
||
517 | if ( strpos( $matches[1], '.ico' ) === false ) { |
||
518 | return $this->replace_img_callback( $matches, $width, $height ); |
||
519 | } else { |
||
520 | return $matches[0]; |
||
521 | } |
||
522 | } |
||
523 | |||
524 | public function filter_optimize_images( $in, $testing = false ) |
||
525 | { |
||
526 | /* |
||
527 | * potential future functional improvements: |
||
528 | * |
||
529 | * filter for critical CSS. |
||
530 | */ |
||
531 | $to_replace = array(); |
||
532 | |||
533 | // hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript). |
||
534 | if ( $this->should_lazyload() ) { |
||
535 | $in = autoptimizeBase::replace_contents_with_marker_if_exists( |
||
536 | 'SCRIPT', |
||
537 | '<script', |
||
538 | '#<(?:no)?script.*?<\/(?:no)?script>#is', |
||
539 | $in |
||
540 | ); |
||
541 | } |
||
542 | |||
543 | // extract img tags. |
||
544 | if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) { |
||
545 | foreach ( $matches[0] as $tag ) { |
||
546 | $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt' , $tag ); |
||
547 | |||
548 | $orig_tag = $tag; |
||
549 | $imgopt_w = ''; |
||
550 | $imgopt_h = ''; |
||
0 ignored issues
–
show
$imgopt_h 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 ![]() |
|||
551 | |||
552 | // first do (data-)srcsets. |
||
553 | if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) { |
||
554 | foreach ( $allsrcsets as $srcset ) { |
||
555 | $srcset = $srcset[2]; |
||
556 | $orig_srcset = $srcset; |
||
557 | $srcsets = explode( ',', $srcset ); |
||
558 | foreach ( $srcsets as $indiv_srcset ) { |
||
559 | $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) ); |
||
560 | if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) { |
||
561 | $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' ); |
||
562 | } |
||
563 | if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) ) { |
||
564 | $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' ); |
||
565 | $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset ); |
||
566 | } |
||
567 | } |
||
568 | $tag = str_replace( $orig_srcset, $srcset, $tag ); |
||
569 | } |
||
570 | } |
||
571 | |||
572 | // proceed with img src. |
||
573 | // get width and height and add to $imgopt_size. |
||
574 | $_get_size = $this->get_size_from_tag( $tag ); |
||
575 | $imgopt_w = $_get_size['width']; |
||
576 | $imgopt_h = $_get_size['height']; |
||
577 | |||
578 | // then start replacing images src. |
||
579 | if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) { |
||
580 | foreach ( $urls as $url ) { |
||
581 | $full_src_orig = $url[0]; |
||
582 | $url = $url[1]; |
||
583 | if ( $this->can_optimize_image( $url, $tag, $testing ) ) { |
||
584 | $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h ); |
||
585 | $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig ); |
||
586 | $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag ); |
||
587 | } |
||
588 | } |
||
589 | } |
||
590 | |||
591 | // do lazyload stuff. |
||
592 | if ( $this->should_lazyload( $in ) && ! empty( $url ) ) { |
||
593 | // first do lpiq placeholder logic. |
||
594 | if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) { |
||
595 | // if all img src have been replaced during srcset, we have to extract the |
||
596 | // origin url from the imgopt one to be able to set a lqip placeholder. |
||
597 | $_url = substr( $url, strpos( $url, '/http' ) + 1 ); |
||
598 | } else { |
||
599 | $_url = $url; |
||
600 | } |
||
601 | |||
602 | $_url = $this->normalize_img_url( $_url ); |
||
603 | |||
604 | $placeholder = ''; |
||
605 | if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true, $_url ) ) { |
||
606 | $lqip_w = ''; |
||
607 | $lqip_h = ''; |
||
608 | if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) { |
||
609 | $lqip_w = ',w_' . $imgopt_w; |
||
610 | } |
||
611 | if ( isset( $imgopt_h ) && ! empty( $imgopt_h ) ) { |
||
612 | $lqip_h = ',h_' . $imgopt_h; |
||
613 | } |
||
614 | $placeholder = $this->get_imgopt_host() . 'client/q_lqip,ret_wait' . $lqip_w . $lqip_h . '/' . $_url; |
||
615 | } |
||
616 | // then call add_lazyload-function with lpiq placeholder if set. |
||
617 | $tag = $this->add_lazyload( $tag, $placeholder ); |
||
618 | } |
||
619 | |||
620 | $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt' , $tag ); |
||
621 | |||
622 | // and add tag to array for later replacement. |
||
623 | if ( $tag !== $orig_tag ) { |
||
624 | $to_replace[ $orig_tag ] = $tag; |
||
625 | } |
||
626 | } |
||
627 | } |
||
628 | |||
629 | // and replace all. |
||
630 | $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in ); |
||
631 | |||
632 | // img thumbnails in e.g. woocommerce. |
||
633 | if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_imgopt_datathumbs', true ) ) { |
||
634 | $out = preg_replace_callback( |
||
635 | '/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s', |
||
636 | array( $this, 'replace_data_thumbs' ), |
||
637 | $out |
||
638 | ); |
||
639 | } |
||
640 | |||
641 | // background-image in inline style. |
||
642 | View Code Duplication | if ( strpos( $out, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) { |
|
0 ignored issues
–
show
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. ![]() |
|||
643 | $out = preg_replace_callback( |
||
644 | '/style=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)/', |
||
645 | array( $this, 'replace_img_callback' ), |
||
646 | $out |
||
647 | ); |
||
648 | } |
||
649 | |||
650 | // act on icon links. |
||
651 | if ( ( strpos( $out, '<link rel="icon"' ) !== false || ( strpos( $out, "<link rel='icon'" ) !== false ) ) && apply_filters( 'autoptimize_filter_imgopt_linkicon', true ) ) { |
||
652 | $out = preg_replace_callback( |
||
653 | '/<link\srel=(?:"|\')(?:apple-touch-)?icon(?:"|\').*\shref=(?:"|\')(.*)(?:"|\')(?:\ssizes=(?:"|\')(\d*x\d*)(?:"|\'))?\s\/>/Um', |
||
654 | array( $this, 'replace_icon_callback' ), |
||
655 | $out |
||
656 | ); |
||
657 | } |
||
658 | |||
659 | // lazyload: restore noscript tags + lazyload picture source tags and bgimage. |
||
660 | if ( $this->should_lazyload() ) { |
||
661 | $out = autoptimizeBase::restore_marked_content( |
||
662 | 'SCRIPT', |
||
663 | $out |
||
664 | ); |
||
665 | |||
666 | $out = $this->process_picture_tag( $out, true, true ); |
||
667 | $out = $this->process_bgimage( $out ); |
||
668 | } else { |
||
669 | $out = $this->process_picture_tag( $out, true, false ); |
||
670 | } |
||
671 | |||
672 | return $out; |
||
673 | } |
||
674 | |||
675 | public function get_size_from_tag( $tag ) { |
||
676 | // reusable function to extract widht and height from an image tag |
||
677 | // enforcing a filterable maximum width and height (default 4999X4999). |
||
678 | $width = ''; |
||
679 | $height = ''; |
||
680 | |||
681 | if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $_width ) ) { |
||
682 | if ( strpos( $_width[2], '%' ) === false ) { |
||
683 | $width = (int) $_width[2]; |
||
684 | } |
||
685 | } |
||
686 | if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $_height ) ) { |
||
687 | if ( strpos( $_height[2], '%' ) === false ) { |
||
688 | $height = (int) $_height[2]; |
||
689 | } |
||
690 | } |
||
691 | |||
692 | // check for and enforce (filterable) max sizes. |
||
693 | $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 ); |
||
694 | if ( $width > $_max_width ) { |
||
695 | $_width = $_max_width; |
||
696 | $height = $_width / $width * $height; |
||
697 | $width = $_width; |
||
698 | } |
||
699 | $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 ); |
||
700 | if ( $height > $_max_height ) { |
||
701 | $_height = $_max_height; |
||
702 | $width = $_height / $height * $width; |
||
703 | $height = $_height; |
||
704 | } |
||
705 | |||
706 | return array( |
||
707 | 'width' => $width, |
||
708 | 'height' => $height, |
||
709 | ); |
||
710 | } |
||
711 | |||
712 | /** |
||
713 | * Lazyload functions |
||
714 | */ |
||
715 | public static function should_lazyload_wrapper() { |
||
716 | // needed in autoptimizeMain.php. |
||
717 | $self = new self(); |
||
718 | return $self->should_lazyload(); |
||
719 | } |
||
720 | |||
721 | public function should_lazyload( $context = '' ) { |
||
722 | if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && false === $this->check_nolazy() ) { |
||
723 | $lazyload_return = true; |
||
724 | } else { |
||
725 | $lazyload_return = false; |
||
726 | } |
||
727 | $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context ); |
||
728 | |||
729 | return $lazyload_return; |
||
730 | } |
||
731 | |||
732 | public function check_nolazy() { |
||
733 | if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) { |
||
734 | return true; |
||
735 | } else { |
||
736 | return false; |
||
737 | } |
||
738 | } |
||
739 | |||
740 | public function filter_lazyload_images( $in ) |
||
741 | { |
||
742 | // only used is image optimization is NOT active but lazyload is. |
||
743 | $to_replace = array(); |
||
744 | |||
745 | // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript). |
||
746 | $out = autoptimizeBase::replace_contents_with_marker_if_exists( |
||
747 | 'SCRIPT', |
||
748 | '<script', |
||
749 | '#<(?:no)?script.*?<\/(?:no)?script>#is', |
||
750 | $in |
||
751 | ); |
||
752 | |||
753 | // extract img tags and add lazyload attribs. |
||
754 | if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) { |
||
755 | foreach ( $matches[0] as $tag ) { |
||
756 | if ( $this->should_lazyload( $out ) ) { |
||
757 | $to_replace[ $tag ] = $this->add_lazyload( $tag ); |
||
758 | } |
||
759 | } |
||
760 | $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out ); |
||
761 | } |
||
762 | |||
763 | // and also lazyload picture tag. |
||
764 | $out = $this->process_picture_tag( $out, false, true ); |
||
765 | |||
766 | // and inline style blocks with background-image. |
||
767 | $out = $this->process_bgimage( $out ); |
||
768 | |||
769 | // restore noscript tags. |
||
770 | $out = autoptimizeBase::restore_marked_content( |
||
771 | 'SCRIPT', |
||
772 | $out |
||
773 | ); |
||
774 | |||
775 | return $out; |
||
776 | } |
||
777 | |||
778 | public function add_lazyload( $tag, $placeholder = '' ) { |
||
779 | // adds actual lazyload-attributes to an image node. |
||
780 | $this->lazyload_counter++; |
||
781 | |||
782 | $_lazyload_from_nth = ''; |
||
783 | if ( array_key_exists( 'autoptimize_imgopt_number_field_7', $this->options ) ) { |
||
784 | $_lazyload_from_nth = $this->options['autoptimize_imgopt_number_field_7']; |
||
785 | } |
||
786 | $_lazyload_from_nth = apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', $_lazyload_from_nth ); |
||
787 | |||
788 | if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= $_lazyload_from_nth ) { |
||
789 | $tag = $this->maybe_fix_missing_quotes( $tag ); |
||
790 | |||
791 | // store original tag for use in noscript version. |
||
792 | $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>'; |
||
793 | |||
794 | $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' ); |
||
795 | |||
796 | // insert lazyload class. |
||
797 | $tag = $this->inject_classes_in_tag( $tag, "$lazyload_class " ); |
||
798 | |||
799 | if ( ! $placeholder || empty( $placeholder ) ) { |
||
800 | // get image width & heigth for placeholder fun (and to prevent content reflow). |
||
801 | $_get_size = $this->get_size_from_tag( $tag ); |
||
802 | $width = $_get_size['width']; |
||
803 | $height = $_get_size['height']; |
||
804 | if ( false === $width || empty( $width ) ) { |
||
805 | $width = 210; // default width for SVG placeholder. |
||
806 | } |
||
807 | if ( false === $height || empty( $height ) ) { |
||
808 | $height = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio. |
||
809 | } |
||
810 | |||
811 | // insert the actual lazyload stuff. |
||
812 | // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's. |
||
813 | $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( $width, $height ) ); |
||
814 | } |
||
815 | |||
816 | $tag = preg_replace( '/(\s)src=/', ' src=\'' . $placeholder . '\' data-src=', $tag ); |
||
817 | $tag = preg_replace( '/(\s)srcset=/', ' data-srcset=', $tag ); |
||
818 | |||
819 | // move sizes to data-sizes unless filter says no. |
||
820 | if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_move_sizes', true ) ) { |
||
821 | $tag = str_replace( ' sizes=', ' data-sizes=', $tag ); |
||
822 | } |
||
823 | |||
824 | // add the noscript-tag from earlier. |
||
825 | $tag = $noscript_tag . $tag; |
||
826 | $tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag ); |
||
827 | } |
||
828 | |||
829 | return $tag; |
||
830 | } |
||
831 | |||
832 | public function add_lazyload_js_footer() { |
||
833 | if ( false === autoptimizeMain::should_buffer() ) { |
||
834 | return; |
||
835 | } |
||
836 | |||
837 | // The JS will by default be excluded form autoptimization but this can be changed with a filter. |
||
838 | $noptimize_flag = ''; |
||
839 | if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) { |
||
840 | $noptimize_flag = ' data-noptimize="1"'; |
||
841 | } |
||
842 | |||
843 | $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ ); |
||
844 | $cdn_url = $this->get_cdn_url(); |
||
845 | if ( ! empty( $cdn_url ) ) { |
||
846 | $cdn_url = rtrim( $cdn_url, '/' ); |
||
847 | $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js ); |
||
848 | } |
||
849 | |||
850 | $type_js = ''; |
||
851 | if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) { |
||
852 | $type_js = ' type="text/javascript"'; |
||
853 | } |
||
854 | |||
855 | // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async). |
||
856 | echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' ); |
||
857 | echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' ); |
||
858 | echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' ); |
||
859 | |||
860 | // And add webp detection and loading JS. |
||
861 | if ( $this->should_ngimg() ) { |
||
862 | // Add AVIF code, can be disabled for now to only do webp. |
||
863 | if ( apply_filters( 'autoptimize_filter_imgopt_do_avif', true ) ) { |
||
864 | $_ngimg_detect = 'function c_img(a,b){src="avif"==b?"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABoAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACJtZGF0EgAKCBgADsgQEAwgMgwf8AAAWAAAAACvJ+o=":"data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";var c=new Image;c.onload=function(){var d=0<c.width&&0<c.height;a(d,b)},c.onerror=function(){a(!1,b)},c.src=src}function s_img(a,b){w=window,"avif"==b?!1==a?c_img(s_img,"webp"):w.ngImg="avif":!1==a?w.ngImg=!1:w.ngImg="webp"}c_img(s_img,"avif");'; |
||
865 | $_ngimg_load = 'document.addEventListener("lazybeforeunveil",function({target:a}){window.ngImg&&["data-src","data-srcset"].forEach(function(b){attr=a.getAttribute(b),null!==attr&&-1==attr.indexOf("/client/to_")&&a.setAttribute(b,attr.replace(/\/client\//,"/client/to_"+window.ngImg+","))})});'; |
||
866 | } else { |
||
867 | $_ngimg_detect = "function c_webp(A){var n=new Image;n.onload=function(){var e=0<n.width&&0<n.height;A(e)},n.onerror=function(){A(!1)},n.src='data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA=='}function s_webp(e){window.supportsWebP=e}c_webp(s_webp);"; |
||
868 | $_ngimg_load = "document.addEventListener('lazybeforeunveil',function({target:b}){window.supportsWebP&&['data-src','data-srcset'].forEach(function(c){attr=b.getAttribute(c),null!==attr&&-1==attr.indexOf('/client/to_webp')&&b.setAttribute(c,attr.replace(/\/client\//,'/client/to_webp,'))})});"; |
||
869 | } |
||
870 | // Keeping autoptimize_filter_imgopt_webp_js filter for now, but it is deprecated as not only for webp any more. |
||
871 | $_ngimg_output = apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $type_js . $noptimize_flag . '>' . $_ngimg_detect . $_ngimg_load . '</script>' ); |
||
872 | echo apply_filters( 'autoptimize_filter_imgopt_ngimg_js', $_ngimg_output ); |
||
873 | } |
||
874 | } |
||
875 | |||
876 | public function get_cdn_url() { |
||
877 | // getting CDN url here to avoid having to make bigger changes to autoptimizeBase. |
||
878 | static $cdn_url = null; |
||
879 | |||
880 | if ( null === $cdn_url ) { |
||
881 | $cdn_url = autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' ); |
||
882 | $cdn_url = autoptimizeUtils::tweak_cdn_url_if_needed( $cdn_url ); |
||
883 | $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url ); |
||
884 | } |
||
885 | |||
886 | return $cdn_url; |
||
887 | } |
||
888 | |||
889 | public function get_lazyload_exclusions() { |
||
890 | // returns array of strings that if found in an <img tag will stop the img from being lazy-loaded. |
||
891 | static $exclude_lazyload_array = null; |
||
892 | |||
893 | if ( null === $exclude_lazyload_array ) { |
||
894 | $options = $this->options; |
||
895 | |||
896 | // set default exclusions. |
||
897 | $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg', 'loading="eager"' ); |
||
898 | |||
899 | // add from setting. |
||
900 | if ( array_key_exists( 'autoptimize_imgopt_text_field_5', $options ) ) { |
||
901 | $exclude_lazyload_option = $options['autoptimize_imgopt_text_field_5']; |
||
902 | View Code Duplication | if ( ! empty( $exclude_lazyload_option ) ) { |
|
0 ignored issues
–
show
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. ![]() |
|||
903 | $exclude_lazyload_array = array_merge( $exclude_lazyload_array, array_filter( array_map( 'trim', explode( ',', $options['autoptimize_imgopt_text_field_5'] ) ) ) ); |
||
904 | } |
||
905 | } |
||
906 | |||
907 | // and filter for developer-initiated changes. |
||
908 | $exclude_lazyload_array = apply_filters( 'autoptimize_filter_imgopt_lazyload_exclude_array', $exclude_lazyload_array ); |
||
909 | } |
||
910 | |||
911 | return $exclude_lazyload_array; |
||
912 | } |
||
913 | |||
914 | public function inject_classes_in_tag( $tag, $target_class ) { |
||
915 | if ( strpos( $tag, 'class=' ) !== false ) { |
||
916 | $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag ); |
||
917 | } else { |
||
918 | $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag ); |
||
919 | } |
||
920 | |||
921 | return $tag; |
||
922 | } |
||
923 | |||
924 | public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) { |
||
925 | 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'; |
||
926 | } |
||
927 | |||
928 | public function should_ngimg() { |
||
929 | static $ngimg_return = null; |
||
930 | |||
931 | if ( is_null( $ngimg_return ) ) { |
||
932 | // webp only works if imgopt and lazyload are also active. |
||
933 | if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) { |
||
934 | $ngimg_return = true; |
||
935 | } else { |
||
936 | $ngimg_return = false; |
||
937 | } |
||
938 | } |
||
939 | |||
940 | return $ngimg_return; |
||
941 | } |
||
942 | |||
943 | public function process_picture_tag( $in, $imgopt = false, $lazy = false ) { |
||
944 | // check if "<picture" is present and if filter allows us to process <picture>. |
||
945 | if ( strpos( $in, '<picture' ) === false || apply_filters( 'autoptimize_filter_imgopt_dopicture', true ) === false ) { |
||
946 | return $in; |
||
947 | } |
||
948 | |||
949 | $_exclusions = $this->get_lazyload_exclusions(); |
||
950 | $to_replace_pict = array(); |
||
951 | |||
952 | // extract and process each picture-node. |
||
953 | preg_match_all( '#<picture.*</picture>#Usmi', $in, $_pictures, PREG_SET_ORDER ); |
||
954 | foreach ( $_pictures as $_picture ) { |
||
0 ignored issues
–
show
The expression
$_pictures of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
955 | $_picture = $this->maybe_fix_missing_quotes( $_picture ); |
||
956 | if ( strpos( $_picture[0], '<source ' ) !== false && preg_match_all( '#<source .*srcset=(?:"|\')(?!data)(.*)(?:"|\').*>#Usmi', $_picture[0], $_sources, PREG_SET_ORDER ) !== false ) { |
||
957 | foreach ( $_sources as $_source ) { |
||
0 ignored issues
–
show
The expression
$_sources of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
958 | $_picture_replacement = $_source[0]; |
||
959 | |||
960 | // should we optimize the image? |
||
961 | if ( $imgopt && $this->can_optimize_image( $_source[1], $_picture[0] ) ) { |
||
962 | $_picture_replacement = str_replace( $_source[1], $this->build_imgopt_url( $_source[1] ), $_picture_replacement ); |
||
963 | } |
||
964 | // should we lazy-load? |
||
965 | if ( $lazy && $this->should_lazyload() && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) { |
||
966 | $_picture_replacement = str_replace( ' srcset=', ' data-srcset=', $_picture_replacement ); |
||
967 | } |
||
968 | $to_replace_pict[ $_source[0] ] = $_picture_replacement; |
||
969 | } |
||
970 | } |
||
971 | } |
||
972 | |||
973 | // and return the fully procesed $in. |
||
974 | $out = str_replace( array_keys( $to_replace_pict ), array_values( $to_replace_pict ), $in ); |
||
975 | |||
976 | return $out; |
||
977 | } |
||
978 | |||
979 | public function process_bgimage( $in ) { |
||
980 | View Code Duplication | if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) { |
|
0 ignored issues
–
show
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. ![]() |
|||
981 | $out = preg_replace_callback( |
||
982 | '/(<(?:article|aside|body|div|footer|header|p|section|span|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/', |
||
983 | array( $this, 'lazyload_bgimg_callback' ), |
||
984 | $in |
||
985 | ); |
||
986 | return $out; |
||
987 | } |
||
988 | return $in; |
||
989 | } |
||
990 | |||
991 | public function lazyload_bgimg_callback( $matches ) { |
||
992 | if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) { |
||
993 | // get placeholder & lazyload class strings. |
||
994 | $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) ); |
||
995 | $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' ); |
||
996 | // replace background-image URL with SVG placeholder. |
||
997 | $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $matches[0] ); |
||
998 | // sanitize bgimg src for quote sillyness. |
||
999 | $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] ); |
||
1000 | // add data-bg attribute with real background-image URL for lazyload to pick up. |
||
1001 | $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $bgimg_src . '"', $out ); |
||
1002 | // and finally add lazyload class to tag. |
||
1003 | $out = $this->inject_classes_in_tag( $out, "$lazyload_class " ); |
||
1004 | return $out; |
||
1005 | } |
||
1006 | return $matches[0]; |
||
1007 | } |
||
1008 | |||
1009 | public function fix_silly_bgimg_quotes( $tag_in ) { |
||
1010 | // some themes/ pagebuilders wrap backgroundimages in HTML-encoded quotes (or linebreaks) which breaks imgopt/ lazyloading, this removes them. |
||
1011 | return trim( str_replace( array( "\r\n", '"', '"', ''', ''' ), '', $tag_in ) ); |
||
1012 | } |
||
1013 | |||
1014 | public function maybe_fix_missing_quotes( $tag_in ) { |
||
1015 | // 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. |
||
1016 | if ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) { |
||
1017 | $tag_out = preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in ); |
||
1018 | $tag_out = preg_replace( '/\s(width|height)=(?:"|\')?([^\s"\'>]*)(?:"|\')?/', ' $1=\'$2\'', $tag_out ); |
||
1019 | return $tag_out; |
||
1020 | } else { |
||
1021 | return $tag_in; |
||
1022 | } |
||
1023 | } |
||
1024 | |||
1025 | /** |
||
1026 | * Admin page logic and related functions below. |
||
1027 | */ |
||
1028 | public function imgopt_admin_menu() |
||
1029 | { |
||
1030 | // no acces if multisite and not network admin and no site config allowed. |
||
1031 | if ( autoptimizeConfig::should_show_menu_tabs() ) { |
||
1032 | add_submenu_page( |
||
1033 | null, |
||
1034 | 'autoptimize_imgopt', |
||
1035 | 'autoptimize_imgopt', |
||
1036 | 'manage_options', |
||
1037 | 'autoptimize_imgopt', |
||
1038 | array( $this, 'imgopt_options_page' ) |
||
1039 | ); |
||
1040 | } |
||
1041 | register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' ); |
||
1042 | } |
||
1043 | |||
1044 | public function add_imgopt_tab( $in ) |
||
1045 | { |
||
1046 | if ( autoptimizeConfig::should_show_menu_tabs() ) { |
||
1047 | $in = array_merge( $in, array( 'autoptimize_imgopt' => __( 'Images', 'autoptimize' ) ) ); |
||
1048 | } |
||
1049 | |||
1050 | return $in; |
||
1051 | } |
||
1052 | |||
1053 | public function imgopt_options_page() |
||
1054 | { |
||
1055 | // Check querystring for "refreshCacheChecker" and call cachechecker if so. |
||
1056 | if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) { |
||
1057 | $this->query_img_provider_stats( true ); |
||
1058 | } |
||
1059 | |||
1060 | $options = $this->fetch_options(); |
||
1061 | $sp_url_suffix = $this->get_service_url_suffix(); |
||
1062 | ?> |
||
1063 | <style> |
||
1064 | #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;} |
||
1065 | #ao_settings_form .form-table th {font-weight: normal;} |
||
1066 | #autoptimize_imgopt_descr{font-size: 120%;} |
||
1067 | </style> |
||
1068 | <script>document.title = "Autoptimize: <?php _e( 'Images', 'autoptimize' ); ?> " + document.title;</script> |
||
1069 | <div class="wrap"> |
||
1070 | <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1> |
||
1071 | <?php echo autoptimizeConfig::ao_admin_tabs(); ?> |
||
1072 | <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?> |
||
1073 | <div class="notice-warning notice"><p> |
||
1074 | <?php |
||
1075 | // translators: "Autoptimize support forum" will appear in a "a href". |
||
1076 | echo sprintf( __( '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>' ); |
||
1077 | ?> |
||
1078 | </p></div> |
||
1079 | <?php } ?> |
||
1080 | |||
1081 | <?php if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! autoptimizeImages::instance()->launch_ok() ) { ?> |
||
0 ignored issues
–
show
The expression
\autoptimizeImages::instance()->launch_ok() of type null|boolean is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
1082 | <div class="notice-warning notice"><p> |
||
1083 | <?php _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' ); ?> |
||
1084 | </p></div> |
||
1085 | <?php } ?> |
||
1086 | |||
1087 | <?php if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) { ?> |
||
1088 | <div class="notice-warning notice"><p> |
||
1089 | <?php |
||
1090 | // translators: "disable Jetpack's site accelerator for images" will appear in a "a href" linking to the jetpack settings page. |
||
1091 | echo sprintf( __( '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>' ); |
||
1092 | ?> |
||
1093 | </p></div> |
||
1094 | <?php } ?> |
||
1095 | <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'> |
||
1096 | <?php settings_fields( 'autoptimize_imgopt_settings' ); ?> |
||
1097 | <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2> |
||
1098 | <span id='autoptimize_imgopt_descr'><?php _e( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, WebP and AVIF support included!', 'autoptimize' ); ?></span> |
||
1099 | <table class="form-table"> |
||
1100 | <tr> |
||
1101 | <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th> |
||
1102 | <td> |
||
1103 | <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 _e( 'Optimize images on the fly and serve them from Shortpixel\'s global CDN.', 'autoptimize' ); ?></label> |
||
1104 | <?php |
||
1105 | // show shortpixel status. |
||
1106 | $_notice = autoptimizeImages::instance()->get_imgopt_status_notice(); |
||
1107 | if ( $_notice ) { |
||
1108 | switch ( $_notice['status'] ) { |
||
1109 | case 2: |
||
1110 | $_notice_color = 'green'; |
||
1111 | break; |
||
1112 | case 1: |
||
1113 | $_notice_color = 'orange'; |
||
1114 | break; |
||
1115 | case -1: |
||
1116 | case -2: |
||
1117 | case -3: |
||
1118 | $_notice_color = 'red'; |
||
1119 | break; |
||
1120 | default: |
||
1121 | $_notice_color = 'green'; |
||
1122 | } |
||
1123 | echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' ); |
||
1124 | } else { |
||
1125 | // translators: link points to shortpixel. |
||
1126 | $upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love by speeding up your website. Start serving on-the-fly optimized images (also in the "next-gen" <strong>WebP</strong> and <strong>AVIF</strong> image formats) by %1$sShortPixel%2$s. The optimized images are cached and served from %3$sShortPixel\'s global CDN%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://help.shortpixel.com/article/62-where-does-the-cdn-has-pops" target="_blank">' ); |
||
1127 | if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) { |
||
1128 | $upsell_msg_2 = __( 'For a limited time only, this service is offered free for all Autoptimize users, <b>don\'t miss the chance to test it</b> and see how much it could improve your site\'s speed.', 'autoptimize' ); |
||
1129 | } else { |
||
1130 | // translators: link points to shortpixel. |
||
1131 | $upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive x2 more CDN traffic or image optimization credits for free! This offer also applies to any future plan that you\'ll choose to purchase.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' ); |
||
1132 | } |
||
1133 | echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' ); |
||
1134 | } |
||
1135 | // translators: link points to shortpixel FAQ. |
||
1136 | $faqcopy = sprintf( __( '<strong>Questions</strong>? Have 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>' ); |
||
1137 | $faqcopy = $faqcopy . ' ' . __( 'Only works for websites and images that are publicly available.', 'autoptimize' ); |
||
1138 | // translators: links points to shortpixel TOS & Privacy Policy. |
||
1139 | $toscopy = sprintf( __( '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/pp' . $sp_url_suffix . '" target="_blank">', '</a>' ); |
||
1140 | echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' ); |
||
1141 | ?> |
||
1142 | </td> |
||
1143 | </tr> |
||
1144 | View Code Duplication | <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"'; } ?>> |
|
0 ignored issues
–
show
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. ![]() |
|||
1145 | <th scope="row"><?php _e( 'Optimization exclusions', 'autoptimize' ); ?></th> |
||
1146 | <td> |
||
1147 | <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 _e( 'Comma-separated list of image classes or filenames that should not be optimized.', 'autoptimize' ); ?></label> |
||
1148 | </td> |
||
1149 | </tr> |
||
1150 | View Code Duplication | <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"'; } ?>> |
|
0 ignored issues
–
show
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. ![]() |
|||
1151 | <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th> |
||
1152 | <td> |
||
1153 | <label> |
||
1154 | <select name='autoptimize_imgopt_settings[autoptimize_imgopt_select_field_2]'> |
||
1155 | <?php |
||
1156 | $_imgopt_array = autoptimizeImages::instance()->get_img_quality_array(); |
||
1157 | $_imgopt_val = autoptimizeImages::instance()->get_img_quality_setting(); |
||
1158 | |||
1159 | foreach ( $_imgopt_array as $key => $value ) { |
||
1160 | echo '<option value="' . $key . '"'; |
||
1161 | if ( $_imgopt_val == $key ) { |
||
1162 | echo ' selected'; |
||
1163 | } |
||
1164 | echo '>' . ucfirst( $value ) . '</option>'; |
||
1165 | } |
||
1166 | echo "\n"; |
||
1167 | ?> |
||
1168 | </select> |
||
1169 | </label> |
||
1170 | <p> |
||
1171 | <?php |
||
1172 | // translators: link points to shortpixel image test page. |
||
1173 | echo apply_filters( 'autoptimize_imgopt_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) ); |
||
1174 | ?> |
||
1175 | </p> |
||
1176 | </td> |
||
1177 | </tr> |
||
1178 | View Code Duplication | <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"'; } ?>> |
|
0 ignored issues
–
show
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. ![]() |
|||
1179 | <th scope="row"><?php _e( 'Load WebP or AVIF in supported browsers?', 'autoptimize' ); ?></th> |
||
1180 | <td> |
||
1181 | <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_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve "next-gen" WebP or AVIF image formats to any browser that supports it (requires lazy load to be active).', 'autoptimize' ); ?></label> |
||
1182 | </td> |
||
1183 | </tr> |
||
1184 | <tr> |
||
1185 | <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th> |
||
1186 | <td> |
||
1187 | <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 _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> |
||
1188 | </td> |
||
1189 | </tr> |
||
1190 | View Code Duplication | <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"'; } ?>> |
|
0 ignored issues
–
show
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. ![]() |
|||
1191 | <th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th> |
||
1192 | <td> |
||
1193 | <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 _e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label> |
||
1194 | </td> |
||
1195 | </tr> |
||
1196 | View Code Duplication | <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"'; } ?>> |
|
0 ignored issues
–
show
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. ![]() |
|||
1197 | <th scope="row"><?php _e( 'Lazy-load from nth image', 'autoptimize' ); ?></th> |
||
1198 | <td> |
||
1199 | <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 '0'; } ?>'><br /><?php _e( 'Don\'t lazyload the first X images, \'0\' lazyloads all.', 'autoptimize' ); ?></label> |
||
1200 | </td> |
||
1201 | </tr> |
||
1202 | </table> |
||
1203 | <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p> |
||
1204 | </form> |
||
1205 | <script> |
||
1206 | jQuery(document).ready(function() { |
||
1207 | jQuery("#autoptimize_imgopt_checkbox").change(function() { |
||
1208 | if (this.checked) { |
||
1209 | jQuery("#autoptimize_imgopt_quality").show("slow"); |
||
1210 | jQuery("#autoptimize_imgopt_ngimg").show("slow"); |
||
1211 | jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow"); |
||
1212 | } else { |
||
1213 | jQuery("#autoptimize_imgopt_quality").hide("slow"); |
||
1214 | jQuery("#autoptimize_imgopt_ngimg").hide("slow"); |
||
1215 | jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow"); |
||
1216 | } |
||
1217 | }); |
||
1218 | jQuery("#autoptimize_imgopt_ngimg_checkbox").change(function() { |
||
1219 | if (this.checked) { |
||
1220 | jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true; |
||
1221 | jQuery(".autoptimize_lazyload_child").show("slow"); |
||
1222 | } |
||
1223 | }); |
||
1224 | jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() { |
||
1225 | if (this.checked) { |
||
1226 | jQuery(".autoptimize_lazyload_child").show("slow"); |
||
1227 | } else { |
||
1228 | jQuery(".autoptimize_lazyload_child").hide("slow"); |
||
1229 | jQuery("#autoptimize_imgopt_ngimg_checkbox")[0].checked = false; |
||
1230 | } |
||
1231 | }); |
||
1232 | }); |
||
1233 | </script> |
||
1234 | <?php |
||
1235 | } |
||
1236 | |||
1237 | /** |
||
1238 | * Ïmg opt status as used on dashboard. |
||
1239 | */ |
||
1240 | public function get_imgopt_status_notice() { |
||
1241 | if ( $this->imgopt_active() ) { |
||
1242 | $_imgopt_notice = ''; |
||
0 ignored issues
–
show
$_imgopt_notice 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 ![]() |
|||
1243 | $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' ); |
||
1244 | $_site_host = AUTOPTIMIZE_SITE_DOMAIN; |
||
1245 | $_imgopt_upsell = 'https://shortpixel.com/aospai/af/SPZURYE109483/' . $_site_host; |
||
1246 | $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account'; |
||
1247 | $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai'; |
||
1248 | |||
1249 | if ( is_array( $_stat ) ) { |
||
1250 | if ( 1 == $_stat['Status'] ) { |
||
1251 | // translators: "add more credits" will appear in a "a href". |
||
1252 | $_imgopt_notice = sprintf( __( '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.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' ); |
||
1253 | } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) { |
||
1254 | // translators: "add more credits" will appear in a "a href". |
||
1255 | $_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota was used, %1$sadd more credits%2$s to keep fast serving optimized images on your site', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' ); |
||
1256 | // translators: "associate your domain" will appear in a "a href". |
||
1257 | $_imgopt_notice = $_imgopt_notice . ' ' . sprintf( __( '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>' ); |
||
1258 | } elseif ( -3 == $_stat['Status'] ) { |
||
1259 | // translators: "check the documentation here" will appear in a "a href". |
||
1260 | $_imgopt_notice = sprintf( __( '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>' ); |
||
1261 | } else { |
||
1262 | $_imgopt_upsell = 'https://shortpixel.com/g/af/SPZURYE109483'; |
||
1263 | // translators: "log in to check your account" will appear in a "a href". |
||
1264 | $_imgopt_notice = sprintf( __( '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>' ); |
||
1265 | } |
||
1266 | |||
1267 | // add info on freshness + refresh link if status is not 2 (good shape). |
||
1268 | if ( 2 != $_stat['Status'] ) { |
||
1269 | $_imgopt_stats_refresh_url = add_query_arg( array( |
||
1270 | 'page' => 'autoptimize_imgopt', |
||
1271 | 'refreshImgProvStats' => '1', |
||
1272 | ), admin_url( 'options-general.php' ) ); |
||
1273 | if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) { |
||
0 ignored issues
–
show
The expression
$_stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
1274 | $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] ); |
||
1275 | } else { |
||
1276 | $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' ); |
||
1277 | } |
||
1278 | $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', '; |
||
1279 | // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats. |
||
1280 | $_imgopt_notice .= sprintf( __( 'you can click %1$shere to refresh your quota status%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' ); |
||
1281 | } |
||
1282 | |||
1283 | // and make the full notice filterable. |
||
1284 | $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice ); |
||
1285 | |||
1286 | return array( |
||
1287 | 'status' => $_stat['Status'], |
||
1288 | 'notice' => $_imgopt_notice, |
||
1289 | ); |
||
1290 | } |
||
1291 | } |
||
1292 | return false; |
||
1293 | } |
||
1294 | |||
1295 | public static function get_imgopt_status_notice_wrapper() { |
||
1296 | // needed for notice being shown in autoptimizeCacheChecker.php. |
||
1297 | $self = new self(); |
||
1298 | return $self->get_imgopt_status_notice(); |
||
1299 | } |
||
1300 | |||
1301 | /** |
||
1302 | * Get img provider stats (used to display notice). |
||
1303 | */ |
||
1304 | public function query_img_provider_stats( $_refresh = false ) { |
||
1305 | if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) { |
||
1306 | $url = ''; |
||
1307 | $stat_dom = 'https://no-cdn.shortpixel.ai/'; |
||
1308 | $endpoint = $stat_dom . 'read-domain/'; |
||
1309 | $domain = AUTOPTIMIZE_SITE_DOMAIN; |
||
1310 | |||
1311 | // make sure parse_url result makes sense, keeping $url empty if not. |
||
1312 | if ( $domain && ! empty( $domain ) ) { |
||
0 ignored issues
–
show
The expression
$domain of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
1313 | $url = $endpoint . $domain; |
||
1314 | if ( true === $_refresh ) { |
||
1315 | $url = $url . '/refresh'; |
||
1316 | } |
||
1317 | } |
||
1318 | |||
1319 | $url = apply_filters( |
||
1320 | 'autoptimize_filter_imgopt_stat_url', |
||
1321 | $url |
||
1322 | ); |
||
1323 | |||
1324 | // only do the remote call if $url is not empty to make sure no parse_url |
||
1325 | // weirdness results in useless calls. |
||
1326 | View Code Duplication | if ( ! empty( $url ) ) { |
|
0 ignored issues
–
show
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. ![]() |
|||
1327 | $response = wp_remote_get( $url ); |
||
1328 | if ( ! is_wp_error( $response ) ) { |
||
1329 | if ( '200' == wp_remote_retrieve_response_code( $response ) ) { |
||
1330 | $stats = json_decode( wp_remote_retrieve_body( $response ), true ); |
||
1331 | autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_provider_stat', $stats ); |
||
1332 | } |
||
1333 | } |
||
1334 | } |
||
1335 | } |
||
1336 | } |
||
1337 | |||
1338 | public static function get_img_provider_stats() |
||
1339 | { |
||
1340 | // wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker. |
||
1341 | $self = new self(); |
||
1342 | return $self->query_img_provider_stats(); |
||
1343 | } |
||
1344 | |||
1345 | /** |
||
1346 | * Determines and returns the service launch status. |
||
1347 | * |
||
1348 | * @return bool |
||
1349 | */ |
||
1350 | public function launch_ok() |
||
1351 | { |
||
1352 | static $launch_status = null; |
||
1353 | |||
1354 | if ( null === $launch_status ) { |
||
1355 | $avail_imgopt = $this->options['availabilities']['extra_imgopt']; |
||
1356 | $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 ); |
||
1357 | $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' ); |
||
1358 | $launch_status = false; |
||
1359 | if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) { |
||
1360 | $launch_status = true; |
||
1361 | if ( ! $has_launched ) { |
||
1362 | autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_launched', 'on' ); |
||
1363 | } |
||
1364 | } |
||
1365 | } |
||
1366 | |||
1367 | return $launch_status; |
||
1368 | } |
||
1369 | |||
1370 | public static function launch_ok_wrapper() { |
||
1371 | // needed for "plug" notice in autoptimizeMain.php. |
||
1372 | $self = new self(); |
||
1373 | return $self->launch_ok(); |
||
1374 | } |
||
1375 | |||
1376 | public function get_imgopt_provider_userstatus() { |
||
1377 | static $_provider_userstatus = null; |
||
1378 | |||
1379 | if ( is_null( $_provider_userstatus ) ) { |
||
1380 | $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' ); |
||
1381 | if ( is_array( $_stat ) ) { |
||
1382 | if ( array_key_exists( 'Status', $_stat ) ) { |
||
1383 | $_provider_userstatus['Status'] = $_stat['Status']; |
||
1384 | } else { |
||
1385 | // if no stats then we assume all is well. |
||
1386 | $_provider_userstatus['Status'] = 2; |
||
1387 | } |
||
1388 | if ( array_key_exists( 'timestamp', $_stat ) ) { |
||
1389 | $_provider_userstatus['timestamp'] = $_stat['timestamp']; |
||
1390 | } else { |
||
1391 | // if no timestamp then we return "". |
||
1392 | $_provider_userstatus['timestamp'] = ''; |
||
1393 | } |
||
1394 | } else { |
||
1395 | // no provider_stat yet, assume/ return all OK. |
||
1396 | $_provider_userstatus['Status'] = 2; |
||
1397 | $_provider_userstatus['timestamp'] = ''; |
||
1398 | } |
||
1399 | } |
||
1400 | |||
1401 | return $_provider_userstatus; |
||
1402 | } |
||
1403 | } |
||
1404 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: