Completed
Push — master ( fc9d9d...72c4b0 )
by
unknown
03:36
created

LSX_LazyLoadImages   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 168
rs 9.8
c 0
b 0
f 0
wmc 31
lcom 2
cbo 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 19 4
A setup_filters() 0 13 1
A add_scripts() 0 5 1
C filter_images() 0 70 17
A noscripts_remove() 0 5 1
A noscripts_restore() 0 3 1
A add_class() 0 21 3
A is_enabled() 0 3 1
A kses_allowed_html() 0 9 1
A kses_allowed_protocols() 0 4 1
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) return;
3
4
/*
5
 * LSX Lazy Load Images Class
6
 * 
7
 * add_filters availables:
8
 *   lsx_lazyload_is_enabled
9
 *   lsx_lazyload_placeholder_image
10
 * 
11
 * apply_filters availables:
12
 *   lsx_lazyload_filter_images
13
 * 
14
 * Currently filtering:
15
 *   the_content
16
 *   widget_text
17
 *   post_thumbnail_html
18
 *   get_avatar
19
 *   envira_gallery_output_image
20
 */
21
class LSX_LazyLoadImages {
22
	protected static $enabled = true;
23
24
	protected static $noscript_id = 0;
25
	protected static $noscripts   = array();
26
27
	static function init() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
28
		if ( is_admin() )
29
			return;
30
31
		if ( get_theme_mod( 'lsx_lazyload_status', '1' ) === false ) {
32
			self::$enabled = false;
33
			return;
34
		}
35
36
		if ( ! apply_filters( 'lsx_lazyload_is_enabled', true ) ) {
37
			self::$enabled = false;
38
			return;
39
		}
40
41
		add_action( 'wp_enqueue_scripts', array( __CLASS__, 'add_scripts' ) );
42
		add_action( 'wp_head', array( __CLASS__, 'setup_filters' ), 9999 );
43
		add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'kses_allowed_html' ), 10, 2 );
44
		add_filter( 'kses_allowed_protocols', array( __CLASS__, 'kses_allowed_protocols' ) );
45
	}
46
47
	static function setup_filters() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
48
		// WordPress
49
		add_filter( 'the_content', array( __CLASS__, 'filter_images' ), 200 );
50
		add_filter( 'widget_text', array( __CLASS__, 'filter_images' ), 200 );
51
		add_filter( 'post_thumbnail_html', array( __CLASS__, 'filter_images' ), 200 );
52
		add_filter( 'get_avatar', array( __CLASS__, 'filter_images' ), 200 );
53
		
54
		// LSX
55
		add_filter( 'lsx_lazyload_filter_images', array( __CLASS__, 'filter_images' ), 200 );
56
57
		// Envira Gallery
58
		add_filter( 'envira_gallery_output_image', array( __CLASS__, 'filter_images' ), 200 );
59
	}
60
61
	static function add_scripts() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
62
		wp_enqueue_script( 'lazysizes', get_template_directory_uri() .'/js/vendor/lazysizes.min.js', array( 'jquery' ), null, true );
63
		// Plugin that enables use lazysizes in brackground images
64
		//wp_enqueue_script( 'lazysizes', get_template_directory_uri() .'/js/vendor/ls.unveilhooks.min.js', array( 'jquery', 'lazysizes' ), null, true );
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
65
	}
66
67
	static function filter_images( $content ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
68
		if ( ! self::is_enabled() ) {
69
			return $content;
70
		}
71
72
		$http_user_agent = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) );
73
		$http_user_agent = ! empty( $http_user_agent ) ? $http_user_agent : '';
74
75
		if ( is_feed()
76
			|| is_preview()
77
			|| intval( get_query_var( 'print' ) ) == 1
78
			|| intval( get_query_var( 'printpage' ) ) == 1
79
			|| strpos( $http_user_agent, 'Opera Mini' ) !== false
80
		) {
81
			return $content;
82
		}
83
84
		$skip_images_regex = '/class=".*(lazyload|disable-lazyload).*"/';
85
		$placeholder_image = apply_filters( 'lsx_lazyload_placeholder_image', 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' );
86
87
		$matches = array();
88
		$search = array();
89
		$replace = array();
90
		
91
		$content = preg_replace_callback( '~<noscript.+?</noscript>~s', 'self::noscripts_remove', $content );
92
		preg_match_all( '/<img[^>]*>/', $content, $matches );
93
94
		foreach ( $matches[0] as $img_html ) {
95
			if ( ! ( preg_match( $skip_images_regex, $img_html ) ) ) {
96
				$add_class = false;
97
98
				if ( ! preg_match( '/src=[\'"]([^\'"]+)[\'"]/', $img_html ) && preg_match( '/srcset=[\'"]([^\'"]+)[\'"]/', $img_html ) ) {
99
					$replace_html = preg_replace( '/<img(.*?)srcset=/i', '<img$1srcset="' . $placeholder_image . '" data-srcset=', $img_html );
100
101
					if ( preg_match( '/sizes=[\'"]([^\'"]+)[\'"]/', $img_html ) ) {
102
						$replace_html = preg_replace( '/sizes=/i', 'data-sizes=', $replace_html );
103
					} else {
104
						$replace_html = preg_replace( '/data-srcset=/i', 'data-sizes="auto" data-srcset=', $replace_html );
105
					}
106
107
					$add_class = true;
108
				} elseif ( preg_match( '/src=[\'"]([^\'"]+)[\'"]/', $img_html ) ) {
109
					$replace_html = preg_replace( '/<img(.*?)src=/i', '<img$1src="' . $placeholder_image . '" data-src=', $img_html );
110
111
					if ( preg_match( '/srcset=[\'"]([^\'"]+)[\'"]/', $img_html ) ) {
112
						if ( preg_match( '/sizes=[\'"]([^\'"]+)[\'"]/', $img_html ) ) {
113
							$replace_html = preg_replace( '/srcset=/i', 'data-srcset=', $replace_html );
114
							$replace_html = preg_replace( '/sizes=/i', 'data-sizes=', $replace_html );
115
						} else {
116
							$replace_html = preg_replace( '/srcset=/i', 'data-sizes="auto" data-srcset=', $replace_html );
117
						}
118
					}
119
120
					$add_class = true;
121
				}
122
123
				if ( $add_class ) {
124
					$replace_html = self::add_class( $replace_html, 'lazyload' );
0 ignored issues
show
Bug introduced by
The variable $replace_html does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
125
					$replace_html .= '<noscript>' . $img_html . '</noscript>';
126
					
127
					array_push( $search, $img_html );
128
					array_push( $replace, $replace_html );
129
				}
130
			}
131
		}
132
133
		$content = str_replace( $search, $replace, $content );
134
		$content = preg_replace_callback( '~' . chr(20) . '([0-9]+)' . chr(20) . '~', 'self::noscripts_restore', $content );
135
		return $content;
136
	}
137
138
	static function noscripts_remove( $match ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
139
		self::$noscript_id++;
140
		self::$noscripts[self::$noscript_id] = $match[0];
141
		return chr(20) . self::$noscript_id . chr(20);
142
	}
143
144
	static function noscripts_restore( $match ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
145
		return self::$noscripts[(int) $match[1]];
146
	}
147
148
	static function add_class( $html_string = '', $new_class ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
149
		$pattern = '/class=[\'"]([^\'"]*)[\'"]/';
150
151
		if ( preg_match( $pattern, $html_string, $matches ) ) {
152
			$defined_classes = explode( ' ', $matches[1] );
153
154
			if ( ! in_array( $new_class, $defined_classes ) ) {
155
				$defined_classes[] = $new_class;
156
157
				$html_string = str_replace(
158
					$matches[0],
159
					sprintf( 'class="%s"', implode( ' ', $defined_classes ) ),
160
					$html_string
161
				);
162
			}
163
		} else {
164
			$html_string = preg_replace( '/(\<.+\s)/', sprintf( '$1class="%s" ', $new_class ), $html_string );
165
		}
166
167
		return $html_string;
168
	}
169
170
	static function is_enabled() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
171
		return self::$enabled;
172
	}
173
174
	static function kses_allowed_html( $allowedtags, $context ) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
175
		$allowedtags['noscript'] = array();
176
		
177
		$allowedtags['img']['data-src'] = true;
178
		$allowedtags['img']['data-srcset'] = true;
179
		$allowedtags['img']['data-sizes'] = true;
180
181
		return $allowedtags;
182
	}
183
184
	static function kses_allowed_protocols( $allowedprotocols ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
185
		$allowedprotocols[] = 'data';
186
		return $allowedprotocols;
187
	}
188
}
189
190
add_action( 'init', array( 'LSX_LazyLoadImages', 'init' ) );
191