Image optimization & Lazy Load by Optimole - Version 2.0.4

Version Description

Download this release

Release Info

Developer optimole
Plugin Icon 128x128 Image optimization & Lazy Load by Optimole
Version 2.0.4
Comparing to
See all releases

Code changes from version 2.0.3 to 2.0.4

CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
2
 
3
  * **Bug Fixes**
1
+ #### [Version 2.0.4](https://github.com/Codeinwp/optimole-wp/compare/v2.0.3...v2.0.4) (2019-03-11)
2
+
3
+ * **Bug Fixes**
4
+ * adds full compatibility with Envira gallery ([7fd618f](https://github.com/Codeinwp/optimole-wp/commit/7fd618f))
5
+ * compatibility with Foogallery plugin when the gallery uses lazyload too ([67991dc](https://github.com/Codeinwp/optimole-wp/commit/67991dc))
6
+ * compatibility with images which contains query arguments, causing broken image urls ([56108be](https://github.com/Codeinwp/optimole-wp/commit/56108be))
7
+ * compatibility with relative image urls ([8089610](https://github.com/Codeinwp/optimole-wp/commit/8089610))
8
+ * compatibility with Revolution slider, adds support for background images lazyload and exact match ([0bbd254](https://github.com/Codeinwp/optimole-wp/commit/0bbd254))
9
+ * compatibility with shortcode ultimate plugin ([164ba35](https://github.com/Codeinwp/optimole-wp/commit/164ba35))
10
+ * compatibility with Woocommerce, solving issue with zoom image on single product pages ([1692e2b](https://github.com/Codeinwp/optimole-wp/commit/1692e2b))
11
+ * image replacement on WordPress REST api responses ([24d191b](https://github.com/Codeinwp/optimole-wp/commit/24d191b))
12
+ * image url replacement on custom WordPress directory structure, fixes [#79](https://github.com/Codeinwp/optimole-wp/issues/79), thanks [@hackles](https://github.com/hackles) for reporting ([980fcef](https://github.com/Codeinwp/optimole-wp/commit/980fcef))
13
+
14
+ * **Features**
15
+ * tested up compatibility with WordPress 5.1 ([12726b6](https://github.com/Codeinwp/optimole-wp/commit/12726b6))
16
+ * **api:** adds filter for restricting watermark based on image source urls ([337d7fa](https://github.com/Codeinwp/optimole-wp/commit/337d7fa))
17
+ * **api:** adds filter to disable image replacement on a specific page/ur ([3250a8d](https://github.com/Codeinwp/optimole-wp/commit/3250a8d))
18
+
19
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
20
 
21
  * **Bug Fixes**
README.md CHANGED
@@ -2,7 +2,7 @@
2
  **Contributors:** [optimole](https://profiles.wordpress.org/optimole)
3
  **Tags:** image optimization, cdn, image compression, compress image, images, optimization, perfomance, photos
4
  **Requires at least:** 4.7
5
- **Tested up to:** 5.0
6
  **Requires PHP:** 5.4
7
  **License:** GPLv3
8
  **License URI:** https://www.gnu.org/licenses/gpl-3.0.en.html
@@ -91,6 +91,26 @@ Premium users will be able to optimize 10GB images per month with a 50GB viewing
91
 
92
  ## Changelog ##
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
95
 
96
  * **Bug Fixes**
2
  **Contributors:** [optimole](https://profiles.wordpress.org/optimole)
3
  **Tags:** image optimization, cdn, image compression, compress image, images, optimization, perfomance, photos
4
  **Requires at least:** 4.7
5
+ **Tested up to:** 5.1
6
  **Requires PHP:** 5.4
7
  **License:** GPLv3
8
  **License URI:** https://www.gnu.org/licenses/gpl-3.0.en.html
91
 
92
  ## Changelog ##
93
 
94
+ #### [Version 2.0.4](https://github.com/Codeinwp/optimole-wp/compare/v2.0.3...v2.0.4) (2019-03-11)
95
+
96
+ * **Bug Fixes**
97
+ * adds full compatibility with Envira gallery ([7fd618f](https://github.com/Codeinwp/optimole-wp/commit/7fd618f))
98
+ * compatibility with Foogallery plugin when the gallery uses lazyload too ([67991dc](https://github.com/Codeinwp/optimole-wp/commit/67991dc))
99
+ * compatibility with images which contains query arguments, causing broken image urls ([56108be](https://github.com/Codeinwp/optimole-wp/commit/56108be))
100
+ * compatibility with relative image urls ([8089610](https://github.com/Codeinwp/optimole-wp/commit/8089610))
101
+ * compatibility with Revolution slider, adds support for background images lazyload and exact match ([0bbd254](https://github.com/Codeinwp/optimole-wp/commit/0bbd254))
102
+ * compatibility with shortcode ultimate plugin ([164ba35](https://github.com/Codeinwp/optimole-wp/commit/164ba35))
103
+ * compatibility with Woocommerce, solving issue with zoom image on single product pages ([1692e2b](https://github.com/Codeinwp/optimole-wp/commit/1692e2b))
104
+ * image replacement on WordPress REST api responses ([24d191b](https://github.com/Codeinwp/optimole-wp/commit/24d191b))
105
+ * image url replacement on custom WordPress directory structure, fixes [#79](https://github.com/Codeinwp/optimole-wp/issues/79), thanks [@hackles](https://github.com/hackles) for reporting ([980fcef](https://github.com/Codeinwp/optimole-wp/commit/980fcef))
106
+
107
+ * **Features**
108
+ * tested up compatibility with WordPress 5.1 ([12726b6](https://github.com/Codeinwp/optimole-wp/commit/12726b6))
109
+ * **api:** adds filter for restricting watermark based on image source urls ([337d7fa](https://github.com/Codeinwp/optimole-wp/commit/337d7fa))
110
+ * **api:** adds filter to disable image replacement on a specific page/ur ([3250a8d](https://github.com/Codeinwp/optimole-wp/commit/3250a8d))
111
+
112
+
113
+
114
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
115
 
116
  * **Bug Fixes**
inc/admin.php CHANGED
@@ -57,7 +57,12 @@ class Optml_Admin {
57
  public function inline_bootstrap_script() {
58
  $domain = 'https://' . OPTML_JS_CDN;
59
 
60
- $min = ! OPTML_DEBUG ? '.min' : '';
 
 
 
 
 
61
 
62
  $output = sprintf(
63
  '
@@ -72,6 +77,7 @@ class Optml_Admin {
72
  opacity: .75;
73
  filter: blur(5px);
74
  }
 
75
  </style>
76
  <script type="application/javascript">
77
  (function(w, d){
@@ -81,13 +87,21 @@ class Optml_Admin {
81
  s.async = true;
82
  s.src = "%s/v2/latest/optimole_lib" + v + "%s.js";
83
  b.appendChild(s);
 
 
 
 
 
84
 
85
  }(window, document));
86
 
87
  document.addEventListener( "DOMContentLoaded", function() { document.body.className = document.body.className.replace("optimole-no-script",""); } );
88
  </script>',
89
  esc_url( $domain ),
90
- $min
 
 
 
91
  );
92
  echo $output;
93
  }
57
  public function inline_bootstrap_script() {
58
  $domain = 'https://' . OPTML_JS_CDN;
59
 
60
+ $min = ! OPTML_DEBUG ? '.min' : '';
61
+ $bgclasses = Optml_Lazyload_Replacer::get_lazyload_bg_classes();
62
+ $watcher_classes = Optml_Lazyload_Replacer::get_watcher_lz_classes();
63
+
64
+ $bgclasses = empty( $bgclasses ) ? '' : sprintf( '"%s"', implode( '","', (array) $bgclasses ) );
65
+ $watcher_classes = empty( $watcher_classes ) ? '' : sprintf( '"%s"', implode( '","', (array) $watcher_classes ) );
66
 
67
  $output = sprintf(
68
  '
77
  opacity: .75;
78
  filter: blur(5px);
79
  }
80
+
81
  </style>
82
  <script type="application/javascript">
83
  (function(w, d){
87
  s.async = true;
88
  s.src = "%s/v2/latest/optimole_lib" + v + "%s.js";
89
  b.appendChild(s);
90
+ w.optimoleData = {
91
+ backgroundReplaceClasses: [%s],
92
+ watchClasses: [%s],
93
+ quality: %d
94
+ }
95
 
96
  }(window, document));
97
 
98
  document.addEventListener( "DOMContentLoaded", function() { document.body.className = document.body.className.replace("optimole-no-script",""); } );
99
  </script>',
100
  esc_url( $domain ),
101
+ $min,
102
+ $bgclasses,
103
+ $watcher_classes,
104
+ $this->settings->get_numeric_quality()
105
  );
106
  echo $output;
107
  }
inc/api.php CHANGED
@@ -57,7 +57,7 @@ final class Optml_Api {
57
  // Grab the url to which we'll be making the request.
58
  $url = $this->api_root;
59
  $headers = array(
60
- 'Optml-Site' => get_site_url(),
61
  );
62
  if ( ! empty( $this->api_key ) ) {
63
  $headers['Authorization'] = 'Bearer ' . $this->api_key;
@@ -139,7 +139,7 @@ final class Optml_Api {
139
  'POST',
140
  array(
141
  'email' => $email,
142
- 'site' => get_site_url(),
143
  )
144
  );
145
  }
57
  // Grab the url to which we'll be making the request.
58
  $url = $this->api_root;
59
  $headers = array(
60
+ 'Optml-Site' => get_home_url(),
61
  );
62
  if ( ! empty( $this->api_key ) ) {
63
  $headers['Authorization'] = 'Bearer ' . $this->api_key;
139
  'POST',
140
  array(
141
  'email' => $email,
142
+ 'site' => get_home_url(),
143
  )
144
  );
145
  }
inc/app_replacer.php CHANGED
@@ -20,6 +20,24 @@ abstract class Optml_App_Replacer {
20
  * @var array
21
  */
22
  protected static $size_to_crop = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  /**
24
  * Settings handler.
25
  *
@@ -74,6 +92,54 @@ abstract class Optml_App_Replacer {
74
  */
75
  protected $is_allowed_site = array();
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  /**
78
  * Size to crop maping.
79
  *
@@ -149,52 +215,23 @@ abstract class Optml_App_Replacer {
149
  */
150
  public function init() {
151
  $this->settings = new Optml_Settings();
152
-
153
- if ( ! $this->should_replace() ) {
154
- return false; // @codeCoverageIgnore
155
- }
156
  $this->set_properties();
157
 
158
- return true;
159
  }
160
 
161
- /**
162
- * Check if we should rewrite the urls.
163
- *
164
- * @return bool If we can replace the image.
165
- */
166
- public function should_replace() {
167
- if ( Optml_Manager::is_ajax_request() ) {
168
- return true;
169
- }
170
- if ( is_admin() || ! $this->settings->is_connected() || ! $this->settings->is_enabled() || is_customize_preview() ) {
171
- return false; // @codeCoverageIgnore
172
- }
173
-
174
- if ( array_key_exists( 'preview', $_GET ) && 'true' == $_GET['preview'] ) {
175
- return false; // @codeCoverageIgnore
176
- }
177
-
178
- if ( array_key_exists( 'optml_off', $_GET ) && 'true' == $_GET['optml_off'] ) {
179
- return false; // @codeCoverageIgnore
180
- }
181
- if ( array_key_exists( 'elementor-preview', $_GET ) && ! empty( $_GET['elementor-preview'] ) ) {
182
- return false; // @codeCoverageIgnore
183
- }
184
-
185
- return true;
186
- }
187
 
188
  /**
189
  * Set the cdn url based on the current connected user.
190
  */
191
  public function set_properties() {
192
- $upload_data = wp_upload_dir();
193
- $this->upload_resource = array(
 
194
  'url' => str_replace( array( 'https://', 'http://' ), '', $upload_data['baseurl'] ),
195
  'directory' => $upload_data['basedir'],
196
  );
197
- $this->upload_resource['url_length'] = strlen( $this->upload_resource['url'] );
 
198
 
199
  $service_data = $this->settings->get( 'service_data' );
200
 
@@ -209,12 +246,12 @@ abstract class Optml_App_Replacer {
209
  $this->site_mappings['//i2.wp.com/'] = '//';
210
 
211
  if ( defined( 'OPTML_SITE_MIRROR' ) && constant( 'OPTML_SITE_MIRROR' ) ) {
212
- $this->site_mappings[ rtrim( get_site_url(), '/' ) ] = rtrim( constant( 'OPTML_SITE_MIRROR' ), '/' );
213
  }
214
 
215
  $this->possible_sources = $this->extract_domain_from_urls(
216
  array_merge(
217
- array( get_site_url() ),
218
  array_values( $this->site_mappings ),
219
  array_keys( $this->site_mappings )
220
  )
@@ -226,6 +263,9 @@ abstract class Optml_App_Replacer {
226
 
227
  $this->max_height = $this->settings->get( 'max_height' );
228
  $this->max_width = $this->settings->get( 'max_width' );
 
 
 
229
  }
230
 
231
  /**
@@ -279,6 +319,7 @@ abstract class Optml_App_Replacer {
279
  if ( ! isset( $url['host'] ) ) {
280
  return false;
281
  }
 
282
  return isset( $this->possible_sources[ $url['host'] ] ) || isset( $this->allowed_sources[ $url['host'] ] );
283
  }
284
 
@@ -289,9 +330,9 @@ abstract class Optml_App_Replacer {
289
  *
290
  * @return string
291
  **/
292
- protected function strip_image_size_from_url( $url ) {
293
 
294
- if ( preg_match( '#(-\d+x\d+)\.(' . implode( '|', array_keys( Optml_Config::$extensions ) ) . '){1}$#i', $url, $src_parts ) ) {
295
  $stripped_url = str_replace( $src_parts[1], '', $url );
296
  // Extracts the file path to the image minus the base url
297
  $file_path = substr( $stripped_url, strpos( $stripped_url, $this->upload_resource['url'] ) + $this->upload_resource['url_length'] );
@@ -313,15 +354,15 @@ abstract class Optml_App_Replacer {
313
  protected function parse_dimensions_from_filename( $src ) {
314
  $width_height_string = array();
315
  $extensions = array_keys( Optml_Config::$extensions );
316
- if ( preg_match( '#-(\d+)x(\d+)\.(?:' . implode( '|', $extensions ) . '){1}$#i', $src, $width_height_string ) ) {
317
  $width = (int) $width_height_string[1];
318
  $height = (int) $width_height_string[2];
319
-
320
  if ( $width && $height ) {
321
- return array( $width, $height );
322
  }
323
  }
324
 
325
- return array( false, false );
326
  }
327
  }
20
  * @var array
21
  */
22
  protected static $size_to_crop = array();
23
+ /**
24
+ * Holds possible src attributes.
25
+ *
26
+ * @var array
27
+ */
28
+ protected static $possible_src_attributes = null;
29
+ /**
30
+ * Holds possible lazyload flags where we should ignore our lazyload.
31
+ *
32
+ * @var array
33
+ */
34
+ protected static $ignore_lazyload_strings = null;
35
+ /**
36
+ * Holds flags that should ignore the data-opt-tag format.
37
+ *
38
+ * @var array
39
+ */
40
+ protected static $ignore_data_opt_attribute = null;
41
  /**
42
  * Settings handler.
43
  *
92
  */
93
  protected $is_allowed_site = array();
94
 
95
+ /**
96
+ * Returns possible src attributes.
97
+ *
98
+ * @return array
99
+ */
100
+ public static function possible_src_attributes() {
101
+
102
+ if ( null != self::$possible_src_attributes && is_array( self::$possible_src_attributes ) ) {
103
+ return self::$possible_src_attributes;
104
+ }
105
+
106
+ self::$possible_src_attributes = apply_filters( 'optml_possible_src_attributes', [] );
107
+
108
+ return self::$possible_src_attributes;
109
+ }
110
+
111
+ /**
112
+ * Returns possible src attributes.
113
+ *
114
+ * @return array
115
+ */
116
+ public static function possible_lazyload_flags() {
117
+
118
+ if ( null != self::$ignore_lazyload_strings && is_array( self::$ignore_lazyload_strings ) ) {
119
+ return self::$ignore_lazyload_strings;
120
+ }
121
+
122
+ self::$possible_src_attributes = apply_filters( 'optml_possible_lazyload_flags', [] );
123
+
124
+ return array_merge( self::$possible_src_attributes, [ '<noscript' ] );
125
+ }
126
+
127
+ /**
128
+ * Returns possible data-opt-src ignore flags attributes.
129
+ *
130
+ * @return array
131
+ */
132
+ public static function possible_data_ignore_flags() {
133
+
134
+ if ( null != self::$ignore_data_opt_attribute && is_array( self::$ignore_data_opt_attribute ) ) {
135
+ return self::$ignore_data_opt_attribute;
136
+ }
137
+
138
+ self::$ignore_data_opt_attribute = apply_filters( 'optml_ignore_data_opt_flag', [] );
139
+
140
+ return self::$ignore_data_opt_attribute;
141
+ }
142
+
143
  /**
144
  * Size to crop maping.
145
  *
215
  */
216
  public function init() {
217
  $this->settings = new Optml_Settings();
 
 
 
 
218
  $this->set_properties();
219
 
 
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
  /**
224
  * Set the cdn url based on the current connected user.
225
  */
226
  public function set_properties() {
227
+
228
+ $upload_data = wp_upload_dir();
229
+ $this->upload_resource = array(
230
  'url' => str_replace( array( 'https://', 'http://' ), '', $upload_data['baseurl'] ),
231
  'directory' => $upload_data['basedir'],
232
  );
233
+ $this->upload_resource['url_length'] = strlen( $this->upload_resource['url'] );
234
+ $this->upload_resource['content_path'] = str_replace( get_home_url(), '', content_url() );
235
 
236
  $service_data = $this->settings->get( 'service_data' );
237
 
246
  $this->site_mappings['//i2.wp.com/'] = '//';
247
 
248
  if ( defined( 'OPTML_SITE_MIRROR' ) && constant( 'OPTML_SITE_MIRROR' ) ) {
249
+ $this->site_mappings[ rtrim( get_home_url(), '/' ) ] = rtrim( constant( 'OPTML_SITE_MIRROR' ), '/' );
250
  }
251
 
252
  $this->possible_sources = $this->extract_domain_from_urls(
253
  array_merge(
254
+ array( get_home_url() ),
255
  array_values( $this->site_mappings ),
256
  array_keys( $this->site_mappings )
257
  )
263
 
264
  $this->max_height = $this->settings->get( 'max_height' );
265
  $this->max_width = $this->settings->get( 'max_width' );
266
+
267
+ add_filter( 'optml_strip_image_size_from_url', [ $this, 'strip_image_size_from_url' ], 10, 1 );
268
+
269
  }
270
 
271
  /**
319
  if ( ! isset( $url['host'] ) ) {
320
  return false;
321
  }
322
+
323
  return isset( $this->possible_sources[ $url['host'] ] ) || isset( $this->allowed_sources[ $url['host'] ] );
324
  }
325
 
330
  *
331
  * @return string
332
  **/
333
+ public function strip_image_size_from_url( $url ) {
334
 
335
+ if ( preg_match( '#(-\d+x\d+(?:_c)?)\.(' . implode( '|', array_keys( Optml_Config::$extensions ) ) . '){1}$#i', $url, $src_parts ) ) {
336
  $stripped_url = str_replace( $src_parts[1], '', $url );
337
  // Extracts the file path to the image minus the base url
338
  $file_path = substr( $stripped_url, strpos( $stripped_url, $this->upload_resource['url'] ) + $this->upload_resource['url_length'] );
354
  protected function parse_dimensions_from_filename( $src ) {
355
  $width_height_string = array();
356
  $extensions = array_keys( Optml_Config::$extensions );
357
+ if ( preg_match( '#-(\d+)x(\d+)(:?_c)?\.(?:' . implode( '|', $extensions ) . '){1}$#i', $src, $width_height_string ) ) {
358
  $width = (int) $width_height_string[1];
359
  $height = (int) $width_height_string[2];
360
+ $crop = ( isset( $width_height_string[3] ) && $width_height_string[3] === '_c' );
361
  if ( $width && $height ) {
362
+ return array( $width, $height, $crop );
363
  }
364
  }
365
 
366
+ return array( false, false, false );
367
  }
368
  }
inc/compatibilities/compatibility.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Optml_compatibility.
4
+ */
5
+ abstract class Optml_compatibility {
6
+ /**
7
+ * Register compatibility actions/filters.
8
+ */
9
+ abstract function register();
10
+
11
+ /**
12
+ * Should we load the compatibility?
13
+ *
14
+ * @return bool Compatiblity
15
+ */
16
+ abstract function should_load();
17
+ }
inc/compatibilities/envira.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Optml_shortcode_ultimate.
5
+ *
6
+ * @reason The gallery output contains a different src attribute used for lazyload
7
+ * which prevented optimole to parse the tag.
8
+ */
9
+ class Optml_envira extends Optml_compatibility {
10
+
11
+ /**
12
+ * Should we load the integration logic.
13
+ *
14
+ * @return bool Should we load.
15
+ */
16
+ function should_load() {
17
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
18
+
19
+ return ( is_plugin_active( 'envira-gallery-lite/envira-gallery-lite.php' ) || is_plugin_active( 'envira-gallery/envira-gallery.php' ) );
20
+ }
21
+
22
+ /**
23
+ * Register integration details.
24
+ */
25
+ public function register() {
26
+ add_filter( 'optml_possible_src_attributes', [ $this, 'add_lazysrc' ], 10, 3 );
27
+ add_filter( 'optml_possible_lazyload_flags', [ $this, 'add_lazyflag' ], 10, 3 );
28
+ add_filter( 'optml_parse_resize_from_tag', [ $this, 'check_resize_tag' ], 10, 2 );
29
+ add_filter( 'envira_gallery_image_src', [ $this, 'revert_src' ], 10, 1 );
30
+ }
31
+
32
+ /**
33
+ * Revert the optimole url to the original state in
34
+ * order to allow to be parsed by the image tag parser.
35
+ *
36
+ * @param string $image Image url.
37
+ *
38
+ * @return string Original url.
39
+ */
40
+ function revert_src( $image ) {
41
+
42
+ if ( ( $pos = strpos( $image, '/http' ) ) !== false ) {
43
+ return ltrim( substr( $image, $pos ), '/' );
44
+ }
45
+
46
+ return $image;
47
+ }
48
+
49
+ /**
50
+ * Alter default resize for image tag parsing.
51
+ *
52
+ * @param array $old_resize Old array, if any.
53
+ * @param string $tag Image tag.
54
+ *
55
+ * @return array Resize conf.
56
+ */
57
+ function check_resize_tag( $old_resize, $tag ) {
58
+ if ( preg_match( '/(_c)\.(?:' . implode( '|', array_keys( Optml_Config::$extensions ) ) . ')/i', $tag, $match ) ) {
59
+ return [
60
+ 'type' => Optml_Resize::RESIZE_FILL,
61
+ 'gravity' => Optml_Resize::GRAVITY_CENTER,
62
+ ];
63
+ }
64
+
65
+ return [];
66
+ }
67
+
68
+ /**
69
+ * Add envira lazyload flag.
70
+ *
71
+ * @param array $strings Old strings.
72
+ *
73
+ * @return array New flags.
74
+ */
75
+ function add_lazyflag( $strings = array() ) {
76
+
77
+ $strings[] = 'envira-lazy';
78
+
79
+ return $strings;
80
+ }
81
+
82
+ /**
83
+ * Add Envira lazysrc attribute.
84
+ *
85
+ * @param array $attributes Old src attributes.
86
+ *
87
+ * @return array New src attributes.
88
+ */
89
+ function add_lazysrc( $attributes = array() ) {
90
+
91
+ $attributes[] = 'data-envira-src';
92
+
93
+ return $attributes;
94
+ }
95
+ }
inc/compatibilities/foogallery.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Optml_shortcode_ultimate.
5
+ *
6
+ * @reason The gallery output contains a different src attribute used for lazyload
7
+ * which prevented optimole to parse the tag.
8
+ */
9
+ class Optml_foogallery extends Optml_compatibility {
10
+
11
+ /**
12
+ * Should we load the integration logic.
13
+ *
14
+ * @return bool Should we load.
15
+ */
16
+ function should_load() {
17
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
18
+
19
+ return is_plugin_active( 'foogallery/foogallery.php' );
20
+ }
21
+
22
+ /**
23
+ * Register integration details.
24
+ */
25
+ public function register() {
26
+ add_filter( 'optml_possible_src_attributes', [ $this, 'add_lazysrc' ], 10, 3 );
27
+ add_filter( 'optml_possible_lazyload_flags', [ $this, 'add_lazysrc' ], 10, 3 );
28
+ }
29
+
30
+ /**
31
+ * Add foogallery lazysrc attribute.
32
+ *
33
+ * @param array $attributes Old src attributes.
34
+ *
35
+ * @return array New src attributes.
36
+ */
37
+ function add_lazysrc( $attributes = array() ) {
38
+
39
+ $attributes[] = 'data-src-fg';
40
+
41
+ return $attributes;
42
+ }
43
+ }
inc/compatibilities/revslider.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Optml_revslider.
5
+ *
6
+ * @reason The slider output dont needs the data-opt-src and uses a background lazyload approach.
7
+ */
8
+ class Optml_revslider extends Optml_compatibility {
9
+
10
+ /**
11
+ * Should we load the integration logic.
12
+ *
13
+ * @return bool Should we load.
14
+ */
15
+ function should_load() {
16
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
17
+
18
+ return is_plugin_active( 'revslider/revslider.php' );
19
+ }
20
+
21
+ /**
22
+ * Register integration details.
23
+ */
24
+ public function register() {
25
+ add_filter( 'optml_ignore_data_opt_flag', [ $this, 'add_data_ignore' ], 10, 3 );
26
+ add_filter( 'optml_lazyload_bg_classes', [ $this, 'add_bg_class' ], 10, 1 );
27
+ }
28
+
29
+ /**
30
+ * Add classes for lazyload on background.
31
+ *
32
+ * @param string $classes Old classes.
33
+ *
34
+ * @return array New classes.
35
+ */
36
+ public function add_bg_class( $classes = array() ) {
37
+ $classes[] = 'tp-bgimg';
38
+
39
+ return $classes;
40
+ }
41
+
42
+ /**
43
+ * Adds flag that should ignore applying the data-opt-src
44
+ *
45
+ * @param string $flags Flag that should ignore.
46
+ *
47
+ * @return array New flags.
48
+ */
49
+ public function add_data_ignore( $flags = array() ) {
50
+ $flags[] = 'rev-slidebg';
51
+
52
+ return $flags;
53
+ }
54
+
55
+ }
inc/compatibilities/shortcode_ultimate.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Optml_shortcode_ultimate.
5
+ *
6
+ * @reason Shortcode Ultimate uses a strange image resizing feature
7
+ * which has by default the hard cropping on. As we are following the WordPress
8
+ * image size defaults, we need to change the default cropping
9
+ * for shortcode's output.
10
+ */
11
+ class Optml_shortcode_ultimate extends Optml_compatibility {
12
+ /**
13
+ * Tags where we subscribe the compatibility.
14
+ *
15
+ * @var array Allowed tags.
16
+ */
17
+ private $allowed_tags = [
18
+ 'su_slider' => true,
19
+ 'su_carousel' => true,
20
+ 'su_custom_gallery' => true,
21
+ ];
22
+
23
+ /**
24
+ * Should we load the integration logic.
25
+ *
26
+ * @return bool Should we load.
27
+ */
28
+ function should_load() {
29
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
30
+
31
+ return is_plugin_active( 'shortcodes-ultimate/shortcodes-ultimate.php' );
32
+ }
33
+
34
+ /**
35
+ * Register integration details.
36
+ */
37
+ public function register() {
38
+ add_filter( 'do_shortcode_tag', [ $this, 'alter_shortcode_output' ], 10, 3 );
39
+ }
40
+
41
+ /**
42
+ * Alter shortcode output by replacing the image urls.
43
+ *
44
+ * @param string $output Previous shortcode output.
45
+ * @param string $tag Shortcode tag.
46
+ * @param array $attr Shortcode attrs.
47
+ *
48
+ * @return mixed New output.
49
+ */
50
+ function alter_shortcode_output( $output, $tag, $attr ) {
51
+
52
+ if ( ! isset( $this->allowed_tags[ $tag ] ) ) {
53
+ return $output;
54
+ }
55
+
56
+ add_filter( 'optml_default_crop', [ $this, 'change_default_crop' ] );
57
+
58
+ $output = Optml_Main::instance()->manager->process_images_from_content( $output );
59
+
60
+ remove_filter( 'optml_default_crop', [ $this, 'change_default_crop' ] );
61
+
62
+ return $output;
63
+ }
64
+
65
+ /**
66
+ * Change default crop.
67
+ *
68
+ * @return array New default cropping.
69
+ */
70
+ public function change_default_crop() {
71
+ return array(
72
+ 'type' => Optml_Resize::RESIZE_FILL,
73
+ 'gravity' => Optml_Resize::GRAVITY_CENTER,
74
+ );
75
+ }
76
+ }
inc/compatibilities/woocommerce.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Optml_woocommerce.
5
+ *
6
+ * @reason Zoom image on product pages uses a the lqip placeholder instead of the full size image.
7
+ */
8
+ class Optml_woocommerce extends Optml_compatibility {
9
+
10
+ /**
11
+ * Should we load the integration logic.
12
+ *
13
+ * @return bool Should we load.
14
+ */
15
+ function should_load() {
16
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
17
+
18
+ return is_plugin_active( 'woocommerce/woocommerce.php' );
19
+ }
20
+
21
+ /**
22
+ * Register integration details.
23
+ */
24
+ public function register() {
25
+ add_filter( 'optml_watcher_lz_classes', [ $this, 'add_watcher_class' ], 10, 1 );
26
+ }
27
+
28
+ /**
29
+ * Add classes for watching for late lazyload.
30
+ *
31
+ * @param string $classes Old classes.
32
+ *
33
+ * @return array New classes.
34
+ */
35
+ public function add_watcher_class( $classes = array() ) {
36
+ $classes[] = 'zoomImg';
37
+
38
+ return $classes;
39
+ }
40
+
41
+ }
inc/image.php CHANGED
@@ -93,11 +93,11 @@ class Optml_Image {
93
  /**
94
  * Return transformed url.
95
  *
96
- * @param bool $signed Either will be signed or not.
97
  *
98
  * @return string Transformed image url.
99
  */
100
- public function get_url( $signed = false ) {
101
  $path_parts = array();
102
 
103
  $path_parts[] = $this->width->toString();
@@ -108,7 +108,7 @@ class Optml_Image {
108
  $path_parts[] = $this->resize->toString();
109
  }
110
 
111
- if ( is_array( self::$watermark->get() ) && isset( self::$watermark->get()['id'] ) && self::$watermark->get()['id'] > 0 ) {
112
  $path_parts[] = self::$watermark->toString();
113
  }
114
 
@@ -116,7 +116,7 @@ class Optml_Image {
116
 
117
  $path = sprintf( '/%s%s', implode( '/', $path_parts ), $path );
118
 
119
- if ( $signed ) {
120
  $path = sprintf( '/%s%s', $this->get_signature( $path ), $path );
121
  }
122
 
93
  /**
94
  * Return transformed url.
95
  *
96
+ * @param array $params Either will be signed or not.
97
  *
98
  * @return string Transformed image url.
99
  */
100
+ public function get_url( $params = [] ) {
101
  $path_parts = array();
102
 
103
  $path_parts[] = $this->width->toString();
108
  $path_parts[] = $this->resize->toString();
109
  }
110
 
111
+ if ( isset( $params['apply_watermark'] ) && $params['apply_watermark'] && is_array( self::$watermark->get() ) && isset( self::$watermark->get()['id'] ) && self::$watermark->get()['id'] > 0 ) {
112
  $path_parts[] = self::$watermark->toString();
113
  }
114
 
116
 
117
  $path = sprintf( '/%s%s', implode( '/', $path_parts ), $path );
118
 
119
+ if ( isset( $params['signed'] ) && $params['signed'] ) {
120
  $path = sprintf( '/%s%s', $this->get_signature( $path ), $path );
121
  }
122
 
inc/lazyload_replacer.php CHANGED
@@ -16,6 +16,18 @@ final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
16
  * @var Optml_Tag_Replacer
17
  */
18
  protected static $instance = null;
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  /**
21
  * Class instance method.
@@ -27,32 +39,63 @@ final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
27
  * @return Optml_Tag_Replacer
28
  */
29
  public static function instance() {
30
- if ( is_null( self::$instance ) ) {
31
  self::$instance = new self();
32
- add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
33
  }
34
 
35
  return self::$instance;
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * The initialize method.
40
  */
41
  public function init() {
 
42
 
43
- if ( ! parent::init() ) {
44
- return; // @codeCoverageIgnore
45
  }
 
 
 
 
 
 
 
46
 
47
- if ( $this->settings->use_lazyload() ) {
48
- add_filter(
49
- 'max_srcset_image_width',
50
- function () {
51
- return 1;
52
- }
53
- );
54
- add_filter( 'optml_tag_replace', array( $this, 'lazyload_tag_replace' ), 2, 5 );
55
- }
56
  }
57
 
58
  /**
@@ -72,13 +115,17 @@ final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
72
  return Optml_Tag_Replacer::instance()->regular_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed );
73
  }
74
  $optml_args['quality'] = 'eco';
75
- $low_url = apply_filters( 'optml_content_url', $is_slashed ? stripslashes( $original_url ) : $original_url, $optml_args );
76
- $low_url = $is_slashed ? addcslashes( $low_url, '/' ) : $low_url;
77
 
78
- $opt_format = ' data-opt-src="%s" ';
 
 
79
 
80
- $opt_format = $is_slashed ? addslashes( $opt_format ) : $opt_format;
81
- $new_url = $is_slashed ? addcslashes( $new_url, '/' ) : $new_url;
 
 
 
 
82
 
83
  $opt_src = sprintf( $opt_format, $new_url );
84
 
@@ -113,9 +160,12 @@ final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
113
  * @return bool We can lazyload?
114
  */
115
  public function can_lazyload_for( $url, $tag = '' ) {
116
- if ( strpos( $tag, '<noscript' ) !== false ) {
117
- return false;
 
 
118
  }
 
119
  if ( ! defined( 'OPTML_DISABLE_PNG_LAZYLOAD' ) ) {
120
  return true;
121
  }
@@ -135,6 +185,23 @@ final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
135
  return false;
136
  }
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  /**
139
  * Throw error on object clone
140
  *
16
  * @var Optml_Tag_Replacer
17
  */
18
  protected static $instance = null;
19
+ /**
20
+ * Holds classes for listening to lazyload on background.
21
+ *
22
+ * @var array Lazyload background classes.
23
+ */
24
+ private static $lazyload_background_classes = null;
25
+ /**
26
+ * Holds classes responsabile for watching lazyload behaviour.
27
+ *
28
+ * @var array Lazyload classes.
29
+ */
30
+ private static $lazyload_watcher_classes = null;
31
 
32
  /**
33
  * Class instance method.
39
  * @return Optml_Tag_Replacer
40
  */
41
  public static function instance() {
42
+ if ( null === self::$instance ) {
43
  self::$instance = new self();
44
+ add_action( 'optml_replacer_setup', array( self::$instance, 'init' ) );
45
  }
46
 
47
  return self::$instance;
48
  }
49
 
50
+ /**
51
+ * Returns background classes for lazyload.
52
+ *
53
+ * @return array
54
+ */
55
+ public static function get_lazyload_bg_classes() {
56
+
57
+ if ( null != self::$lazyload_background_classes && is_array( self::$lazyload_background_classes ) ) {
58
+ return self::$lazyload_background_classes;
59
+ }
60
+
61
+ self::$lazyload_background_classes = apply_filters( 'optml_lazyload_bg_classes', [] );
62
+
63
+ return self::$lazyload_background_classes;
64
+ }
65
+
66
+ /**
67
+ * Returns classes for lazyload additional watch.
68
+ *
69
+ * @return array
70
+ */
71
+ public static function get_watcher_lz_classes() {
72
+
73
+ if ( null != self::$lazyload_watcher_classes && is_array( self::$lazyload_watcher_classes ) ) {
74
+ return self::$lazyload_watcher_classes;
75
+ }
76
+
77
+ self::$lazyload_watcher_classes = apply_filters( 'optml_watcher_lz_classes', [] );
78
+
79
+ return self::$lazyload_watcher_classes;
80
+ }
81
+
82
  /**
83
  * The initialize method.
84
  */
85
  public function init() {
86
+ parent::init();
87
 
88
+ if ( ! $this->settings->use_lazyload() ) {
89
+ return;
90
  }
91
+ add_filter(
92
+ 'max_srcset_image_width',
93
+ function () {
94
+ return 1;
95
+ }
96
+ );
97
+ add_filter( 'optml_tag_replace', array( $this, 'lazyload_tag_replace' ), 2, 5 );
98
 
 
 
 
 
 
 
 
 
 
99
  }
100
 
101
  /**
115
  return Optml_Tag_Replacer::instance()->regular_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed );
116
  }
117
  $optml_args['quality'] = 'eco';
 
 
118
 
119
+ $low_url = apply_filters( 'optml_content_url', $is_slashed ? stripslashes( $original_url ) : $original_url, $optml_args );
120
+ $low_url = $is_slashed ? addcslashes( $low_url, '/' ) : $low_url;
121
+ $opt_format = '';
122
 
123
+ if ( $this->should_add_data_tag( $new_tag ) ) {
124
+ $opt_format = ' data-opt-src="%s" ';
125
+ $opt_format = $is_slashed ? addslashes( $opt_format ) : $opt_format;
126
+ }
127
+
128
+ $new_url = $is_slashed ? addcslashes( $new_url, '/' ) : $new_url;
129
 
130
  $opt_src = sprintf( $opt_format, $new_url );
131
 
160
  * @return bool We can lazyload?
161
  */
162
  public function can_lazyload_for( $url, $tag = '' ) {
163
+ foreach ( self::possible_lazyload_flags() as $banned_string ) {
164
+ if ( strpos( $tag, $banned_string ) !== false ) {
165
+ return false;
166
+ }
167
  }
168
+
169
  if ( ! defined( 'OPTML_DISABLE_PNG_LAZYLOAD' ) ) {
170
  return true;
171
  }
185
  return false;
186
  }
187
 
188
+ /**
189
+ * Check if we should add the data-opt-tag.
190
+ *
191
+ * @param string $tag Html tag.
192
+ *
193
+ * @return bool Should add?
194
+ */
195
+ public function should_add_data_tag( $tag ) {
196
+ foreach ( self::possible_data_ignore_flags() as $banned_string ) {
197
+ if ( strpos( $tag, $banned_string ) !== false ) {
198
+ return false;
199
+ }
200
+ }
201
+
202
+ return true;
203
+ }
204
+
205
  /**
206
  * Throw error on object clone
207
  *
inc/main.php CHANGED
@@ -13,32 +13,6 @@ final class Optml_Main {
13
  */
14
  private static $_instance = null;
15
 
16
- /**
17
- * Holds the url replacer class.
18
- *
19
- * @access public
20
- * @since 1.0.0
21
- * @var Optml_Url_Replacer Replacer instance.
22
- */
23
- public $url_replacer;
24
-
25
- /**
26
- * Holds the tag replacer class.
27
- *
28
- * @access public
29
- * @since 1.0.0
30
- * @var Optml_Tag_Replacer Replacer instance.
31
- */
32
- public $tag_replacer;
33
-
34
- /**
35
- * Holds the lazyload replacer class.
36
- *
37
- * @access public
38
- * @since 1.0.0
39
- * @var Optml_Lazyload_Replacer Replacer instance.
40
- */
41
- public $lazyload_replacer;
42
 
43
  /**
44
  * Holds the manager class.
@@ -84,20 +58,17 @@ final class Optml_Main {
84
  * @return Optml_Main Plugin instance.
85
  */
86
  public static function instance() {
87
- if ( is_null( self::$_instance ) ) {
88
  add_filter( 'themeisle_sdk_products', array( __CLASS__, 'register_sdk' ) );
89
  add_filter( 'optimole-wp_uninstall_feedback_icon', array( __CLASS__, 'change_icon' ) );
90
  add_filter( 'optimole_wp_uninstall_feedback_after_css', array( __CLASS__, 'adds_uf_css' ) );
91
  add_filter( 'optimole_wp_feedback_review_message', array( __CLASS__, 'change_review_message' ) );
92
  add_filter( 'optimole_wp_logger_heading', array( __CLASS__, 'change_review_message' ) );
93
  add_filter( 'optml_default_settings', array( __CLASS__, 'change_lazyload_default' ) );
94
- self::$_instance = new self();
95
- self::$_instance->url_replacer = Optml_Url_Replacer::instance();
96
- self::$_instance->tag_replacer = Optml_Tag_Replacer::instance();
97
- self::$_instance->lazyload_replacer = Optml_Lazyload_Replacer::instance();
98
- self::$_instance->manager = Optml_Manager::instance();
99
- self::$_instance->rest = new Optml_Rest();
100
- self::$_instance->admin = new Optml_Admin();
101
  }
102
  $vendor_file = OPTML_PATH . 'vendor/autoload.php';
103
  if ( is_readable( $vendor_file ) ) {
13
  */
14
  private static $_instance = null;
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  /**
18
  * Holds the manager class.
58
  * @return Optml_Main Plugin instance.
59
  */
60
  public static function instance() {
61
+ if ( null === self::$_instance ) {
62
  add_filter( 'themeisle_sdk_products', array( __CLASS__, 'register_sdk' ) );
63
  add_filter( 'optimole-wp_uninstall_feedback_icon', array( __CLASS__, 'change_icon' ) );
64
  add_filter( 'optimole_wp_uninstall_feedback_after_css', array( __CLASS__, 'adds_uf_css' ) );
65
  add_filter( 'optimole_wp_feedback_review_message', array( __CLASS__, 'change_review_message' ) );
66
  add_filter( 'optimole_wp_logger_heading', array( __CLASS__, 'change_review_message' ) );
67
  add_filter( 'optml_default_settings', array( __CLASS__, 'change_lazyload_default' ) );
68
+ self::$_instance = new self();
69
+ self::$_instance->manager = Optml_Manager::instance();
70
+ self::$_instance->rest = new Optml_Rest();
71
+ self::$_instance->admin = new Optml_Admin();
 
 
 
72
  }
73
  $vendor_file = OPTML_PATH . 'vendor/autoload.php';
74
  if ( is_readable( $vendor_file ) ) {
inc/manager.php CHANGED
@@ -15,6 +15,52 @@ final class Optml_Manager {
15
  */
16
  protected static $instance = null;
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Class instance method.
20
  *
@@ -25,8 +71,11 @@ final class Optml_Manager {
25
  * @return Optml_Manager
26
  */
27
  public static function instance() {
28
- if ( is_null( self::$instance ) ) {
29
- self::$instance = new self();
 
 
 
30
  add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
31
  }
32
 
@@ -37,22 +86,42 @@ final class Optml_Manager {
37
  * The initialize method.
38
  */
39
  public function init() {
40
- add_filter( 'init', array( $this, 'filter_options_and_mods' ) );
41
- add_filter( 'the_content', array( $this, 'process_images_from_content' ), PHP_INT_MAX );
42
- /**
43
- * When we have to process cdn images, i.e MIRROR is defined,
44
- * we need this as late as possible for other replacers to occur.
45
- * Otherwise, we can hook first to avoid any other plugins to take care of replacement.
46
- */
47
- add_action(
48
- self::is_ajax_request() ? 'init' : 'template_redirect',
49
- array(
50
- $this,
51
- 'process_template_redirect_content',
52
- ),
53
- defined( 'OPTML_SITE_MIRROR' ) ? PHP_INT_MAX : PHP_INT_MIN
54
- );
55
- add_action( 'get_post_metadata', array( $this, 'replace_meta' ), PHP_INT_MAX, 4 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  }
57
 
58
  /**
@@ -81,68 +150,44 @@ final class Optml_Manager {
81
  }
82
 
83
  /**
84
- * Handles the url replacement in options and theme mods.
85
  */
86
- public function filter_options_and_mods() {
 
 
 
 
87
  /**
88
- * `optml_imgcdn_options_with_url` is a filter that allows themes or plugins to select which option
89
- * holds an url and needs an optimization.
 
90
  */
91
- $options_list = apply_filters(
92
- 'optml_imgcdn_options_with_url',
93
  array(
94
- 'theme_mods_' . get_option( 'stylesheet' ),
95
- 'theme_mods_' . get_option( 'template' ),
96
- )
 
97
  );
98
 
99
- foreach ( $options_list as $option ) {
100
- add_filter( "option_$option", array( $this, 'replace_option_url' ) );
101
- }
102
-
103
- }
104
 
105
- /**
106
- * A filter which turns a local url into an optimized CDN image url or an array of image urls.
107
- *
108
- * @param string $url The url which should be replaced.
109
- *
110
- * @return string Replaced url.
111
- */
112
- public function replace_option_url( $url ) {
113
- if ( empty( $url ) ) {
114
- return $url;
115
- }
116
- // $url might be an array or an json encoded array with urls.
117
- if ( is_array( $url ) || filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
118
- $array = $url;
119
- $encoded = false;
120
-
121
- // it might a json encoded array
122
- if ( is_string( $url ) ) {
123
- $array = json_decode( $url, true );
124
- $encoded = true;
125
- }
126
-
127
- // in case there is an array, apply it recursively.
128
- if ( is_array( $array ) ) {
129
- foreach ( $array as $index => $value ) {
130
- $array[ $index ] = $this->replace_option_url( $value );
131
- }
132
-
133
- if ( $encoded ) {
134
- return json_encode( $array );
135
- }
136
-
137
- return $array;
138
- }
139
 
140
- if ( filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
141
- return $url;
 
 
 
 
 
 
 
 
 
142
  }
143
  }
144
-
145
- return apply_filters( 'optml_content_url', $url );
146
  }
147
 
148
  /**
@@ -198,7 +243,7 @@ final class Optml_Manager {
198
  * @return array array of urls.
199
  */
200
  public function extract_urls_from_json( $content ) {
201
- $regex = '/(?<!(=|\\\\)(?:"|\'|"))(?:http(?:s?):)(?:[\/\\\\|.|\w|\s|-])*\.(?:' . implode( '|', array_keys( Optml_Config::$extensions ) ) . ')/';
202
  preg_match_all(
203
  $regex,
204
  $content,
@@ -288,7 +333,6 @@ final class Optml_Manager {
288
  return $content;
289
  }
290
  $images = self::parse_images_from_html( $content );
291
-
292
  if ( empty( $images ) ) {
293
  return $content;
294
  }
@@ -333,7 +377,7 @@ final class Optml_Manager {
333
  $images = array();
334
 
335
  $content = self::strip_header_from_content( $content );
336
- if ( preg_match_all( '/(?:<a[^>]+?href=["|\'](?P<link_url>[^\s]+?)["|\'][^>]*?>\s*)?(?P<img_tag>(?:<\s*noscript\s*>\s*)?<img[^>]*?\s+?src=\\\\?["|\'](?P<img_url>[^\s]+?)["|\'].*?>){1}(?:\s*<\/a>)?/ism', $content, $images ) ) {
337
 
338
  foreach ( $images as $key => $unused ) {
339
  // Simplify the output as much as possible, mostly for confirming test results.
@@ -392,7 +436,7 @@ final class Optml_Manager {
392
  * @return array
393
  */
394
  public function extract_image_urls_from_content( $content ) {
395
- $regex = '/(?:http(?:s?):)(?:[\/\\\\|.|\w|\s|-])*\.(?:' . implode( '|', array_keys( Optml_Config::$extensions ) ) . ')/';
396
  preg_match_all(
397
  $regex,
398
  $content,
15
  */
16
  protected static $instance = null;
17
 
18
+ /**
19
+ * Holds the url replacer class.
20
+ *
21
+ * @access public
22
+ * @since 1.0.0
23
+ * @var Optml_Url_Replacer Replacer instance.
24
+ */
25
+ public $url_replacer;
26
+
27
+ /**
28
+ * Holds the tag replacer class.
29
+ *
30
+ * @access public
31
+ * @since 1.0.0
32
+ * @var Optml_Tag_Replacer Replacer instance.
33
+ */
34
+ public $tag_replacer;
35
+
36
+ /**
37
+ * Holds the lazyload replacer class.
38
+ *
39
+ * @access public
40
+ * @since 1.0.0
41
+ * @var Optml_Lazyload_Replacer Replacer instance.
42
+ */
43
+ public $lazyload_replacer;
44
+ /**
45
+ * Holds plugin settings.
46
+ *
47
+ * @var Optml_Settings WordPress settings.
48
+ */
49
+ protected $settings;
50
+
51
+ /**
52
+ * Possible integrations with different plugins.
53
+ *
54
+ * @var array Integrations classes.
55
+ */
56
+ private $compatibilities = array(
57
+ 'shortcode_ultimate',
58
+ 'foogallery',
59
+ 'envira',
60
+ 'revslider',
61
+ 'woocommerce',
62
+ );
63
+
64
  /**
65
  * Class instance method.
66
  *
71
  * @return Optml_Manager
72
  */
73
  public static function instance() {
74
+ if ( null === self::$instance ) {
75
+ self::$instance = new self();
76
+ self::$instance->url_replacer = Optml_Url_Replacer::instance();
77
+ self::$instance->tag_replacer = Optml_Tag_Replacer::instance();
78
+ self::$instance->lazyload_replacer = Optml_Lazyload_Replacer::instance();
79
  add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
80
  }
81
 
86
  * The initialize method.
87
  */
88
  public function init() {
89
+
90
+ $this->settings = new Optml_Settings();
91
+
92
+ if ( ! $this->should_replace() ) {
93
+ return;
94
+ }
95
+ $this->register_hooks();
96
+ }
97
+
98
+ /**
99
+ * Check if we should rewrite the urls.
100
+ *
101
+ * @return bool If we can replace the image.
102
+ */
103
+ public function should_replace() {
104
+
105
+ if ( apply_filters( 'optml_should_replace_page', false ) ) {
106
+ return false;
107
+ }
108
+
109
+ if ( ( is_admin() && ! self::is_ajax_request() ) || ! $this->settings->is_connected() || ! $this->settings->is_enabled() || is_customize_preview() ) {
110
+ return false; // @codeCoverageIgnore
111
+ }
112
+
113
+ if ( array_key_exists( 'preview', $_GET ) && 'true' == $_GET['preview'] ) {
114
+ return false; // @codeCoverageIgnore
115
+ }
116
+
117
+ if ( array_key_exists( 'optml_off', $_GET ) && 'true' == $_GET['optml_off'] ) {
118
+ return false; // @codeCoverageIgnore
119
+ }
120
+ if ( array_key_exists( 'elementor-preview', $_GET ) && ! empty( $_GET['elementor-preview'] ) ) {
121
+ return false; // @codeCoverageIgnore
122
+ }
123
+
124
+ return true;
125
  }
126
 
127
  /**
150
  }
151
 
152
  /**
153
+ * Register frontend replacer hooks.
154
  */
155
+ public function register_hooks() {
156
+
157
+ do_action( 'optml_replacer_setup' );
158
+
159
+ add_filter( 'the_content', array( $this, 'process_images_from_content' ), PHP_INT_MAX );
160
  /**
161
+ * When we have to process cdn images, i.e MIRROR is defined,
162
+ * we need this as late as possible for other replacers to occur.
163
+ * Otherwise, we can hook first to avoid any other plugins to take care of replacement.
164
  */
165
+ add_action(
166
+ self::is_ajax_request() ? 'init' : 'template_redirect',
167
  array(
168
+ $this,
169
+ 'process_template_redirect_content',
170
+ ),
171
+ defined( 'OPTML_SITE_MIRROR' ) ? PHP_INT_MAX : PHP_INT_MIN
172
  );
173
 
174
+ add_action( 'rest_api_init', array( $this, 'process_template_redirect_content' ), PHP_INT_MIN );
 
 
 
 
175
 
176
+ add_action( 'get_post_metadata', array( $this, 'replace_meta' ), PHP_INT_MAX, 4 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
+ foreach ( $this->compatibilities as $compatibility_class ) {
179
+ $compatibility_class = 'Optml_' . $compatibility_class;
180
+ $compatibility = new $compatibility_class;
181
+
182
+ /**
183
+ * Check if we should load compatibility.
184
+ *
185
+ * @var Optml_compatibility $compatibility Class to register.
186
+ */
187
+ if ( $compatibility->should_load() ) {
188
+ $compatibility->register();
189
  }
190
  }
 
 
191
  }
192
 
193
  /**
243
  * @return array array of urls.
244
  */
245
  public function extract_urls_from_json( $content ) {
246
+ $regex = '/(?<!(=|\\\\)(?:"|\'|"))(?:http(?:s?):)(?:[\/\\\\|.|\w|\s|-])*\.(?:' . implode( '|', array_keys( Optml_Config::$extensions ) ) . ')(?:\??[\w|=|&|\-|\.|:]*)/';
247
  preg_match_all(
248
  $regex,
249
  $content,
333
  return $content;
334
  }
335
  $images = self::parse_images_from_html( $content );
 
336
  if ( empty( $images ) ) {
337
  return $content;
338
  }
377
  $images = array();
378
 
379
  $content = self::strip_header_from_content( $content );
380
+ if ( preg_match_all( '/(?:<a[^>]+?href=["|\'](?P<link_url>[^\s]+?)["|\'][^>]*?>\s*)?(?P<img_tag>(?:<\s*noscript\s*>\s*)?<img[^>]*?\s+?(?:' . implode( '|', array_merge( [ 'src' ], Optml_Tag_Replacer::possible_src_attributes() ) ) . ')=\\\\?["|\'](?P<img_url>[^\s]+?)["|\'].*?>){1}(?:\s*<\/a>)?/ism', $content, $images ) ) {
381
 
382
  foreach ( $images as $key => $unused ) {
383
  // Simplify the output as much as possible, mostly for confirming test results.
436
  * @return array
437
  */
438
  public function extract_image_urls_from_content( $content ) {
439
+ $regex = '/(?:http(?:s?):)(?:[\/\\\\|.|\w|\s|-])*\.(?:' . implode( '|', array_keys( Optml_Config::$extensions ) ) . ')(?:\??[\w|=|&|\-|\.|:]*)/';
440
  preg_match_all(
441
  $regex,
442
  $content,
inc/settings.php CHANGED
@@ -251,6 +251,17 @@ class Optml_Settings {
251
  );
252
  }
253
 
 
 
 
 
 
 
 
 
 
 
 
254
  /**
255
  * Check if replacer is enabled.
256
  *
251
  );
252
  }
253
 
254
+ /**
255
+ * Get numeric quality used by the service.
256
+ *
257
+ * @return int Numeric quality.
258
+ */
259
+ public function get_numeric_quality() {
260
+ $value = $this->get_quality();
261
+
262
+ return (int) $this->to_accepted_quality( $value );
263
+ }
264
+
265
  /**
266
  * Check if replacer is enabled.
267
  *
inc/tag_replacer.php CHANGED
@@ -27,9 +27,9 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
27
  * @return Optml_Tag_Replacer
28
  */
29
  public static function instance() {
30
- if ( is_null( self::$instance ) ) {
31
  self::$instance = new self();
32
- add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
33
  }
34
 
35
  return self::$instance;
@@ -40,18 +40,18 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
40
  */
41
  public function init() {
42
 
43
- if ( ! parent::init() ) {
 
 
 
44
  return;
45
  }
46
 
47
- add_filter( 'optml_content_images_tags', array( $this, 'process_image_tags' ), 1, 2 );
 
 
 
48
 
49
- if ( ! $this->settings->use_lazyload() ) {
50
- add_filter( 'optml_tag_replace', array( $this, 'regular_tag_replace' ), 1, 5 );
51
- add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), PHP_INT_MAX, 3 );
52
- add_filter( 'wp_calculate_image_srcset', array( $this, 'filter_srcset_attr' ), PHP_INT_MAX, 5 );
53
- add_filter( 'wp_calculate_image_sizes', array( $this, 'filter_sizes_attr' ), 1, 2 );
54
- }
55
  }
56
 
57
  /**
@@ -68,20 +68,24 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
68
 
69
  foreach ( $images[0] as $index => $tag ) {
70
  $width = $height = false;
71
- $resize = array();
72
  $new_tag = $tag;
73
 
74
  $is_slashed = strpos( $images['img_url'][ $index ], '\/' ) !== false;
75
 
76
  $src = $tmp = $is_slashed ? stripslashes( $images['img_url'][ $index ] ) : $images['img_url'][ $index ];
77
 
 
 
78
  if ( apply_filters( 'optml_ignore_image_link', false, $src ) ||
79
  false !== strpos( $src, Optml_Config::$service_url ) ||
80
  ! $this->can_replace_url( $src )
81
  ) {
 
82
  continue; // @codeCoverageIgnore
83
  }
84
 
 
 
85
  list( $width, $height, $resize ) = self::parse_dimensions_from_tag(
86
  $images['img_tag'][ $index ],
87
  $image_sizes,
@@ -92,11 +96,12 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
92
  )
93
  );
94
  if ( false === $width && false === $height ) {
95
- list( $width, $height ) = $this->parse_dimensions_from_filename( $tmp );
96
  }
97
-
98
  if ( empty( $resize ) && isset( $sizes2crop[ $width . $height ] ) ) {
99
  $resize = $this->to_optml_crop( $sizes2crop[ $width . $height ] );
 
 
100
  }
101
 
102
  $optml_args = [ 'width' => $width, 'height' => $height, 'resize' => $resize ];
@@ -148,6 +153,7 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
148
  }
149
  if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $tag, $size ) ) {
150
  $size = array_pop( $size );
 
151
  if ( false === $args['width'] && false === $args['height'] && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
152
  $args['width'] = (int) $image_sizes[ $size ]['width'];
153
  $args['height'] = (int) $image_sizes[ $size ]['height'];
@@ -155,6 +161,8 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
155
  if ( 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
156
  $args['resize'] = $this->to_optml_crop( $image_sizes[ $size ]['crop'] );
157
  }
 
 
158
  }
159
 
160
  return array( $args['width'], $args['height'], $args['resize'] );
@@ -196,14 +204,15 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
196
  return $sources;
197
  }
198
  $original_url = null;
199
- $cropping = null;
200
  if ( count( $size_array ) === 2 ) {
201
  $sizes = self::size_to_crop();
202
  $cropping = isset( $sizes[ $size_array[0] . $size_array[1] ] ) ? $this->to_optml_crop( $sizes[ $size_array[0] . $size_array[1] ] ) : null;
203
  }
 
204
  foreach ( $sources as $i => $source ) {
205
  $url = $source['url'];
206
- list( $width, $height ) = $this->parse_dimensions_from_filename( $url );
207
 
208
  if ( empty( $width ) ) {
209
  $width = $image_meta['width'];
@@ -212,6 +221,7 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
212
  if ( empty( $height ) ) {
213
  $height = $image_meta['height'];
214
  }
 
215
  if ( $original_url === null ) {
216
  if ( ! empty( $attachment_id ) ) {
217
  $original_url = wp_get_attachment_url( $attachment_id );
@@ -230,6 +240,8 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
230
  }
231
  if ( $cropping !== null ) {
232
  $args['resize'] = $cropping;
 
 
233
  }
234
  $sources[ $i ]['url'] = apply_filters( 'optml_content_url', $original_url, $args );
235
  }
27
  * @return Optml_Tag_Replacer
28
  */
29
  public static function instance() {
30
+ if ( null === self::$instance ) {
31
  self::$instance = new self();
32
+ add_action( 'optml_replacer_setup', array( self::$instance, 'init' ) );
33
  }
34
 
35
  return self::$instance;
40
  */
41
  public function init() {
42
 
43
+ parent::init();
44
+ add_filter( 'optml_content_images_tags', array( $this, 'process_image_tags' ), 1, 2 );
45
+
46
+ if ( $this->settings->use_lazyload() ) {
47
  return;
48
  }
49
 
50
+ add_filter( 'optml_tag_replace', array( $this, 'regular_tag_replace' ), 1, 5 );
51
+ add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), PHP_INT_MAX, 3 );
52
+ add_filter( 'wp_calculate_image_srcset', array( $this, 'filter_srcset_attr' ), PHP_INT_MAX, 5 );
53
+ add_filter( 'wp_calculate_image_sizes', array( $this, 'filter_sizes_attr' ), 1, 2 );
54
 
 
 
 
 
 
 
55
  }
56
 
57
  /**
68
 
69
  foreach ( $images[0] as $index => $tag ) {
70
  $width = $height = false;
 
71
  $new_tag = $tag;
72
 
73
  $is_slashed = strpos( $images['img_url'][ $index ], '\/' ) !== false;
74
 
75
  $src = $tmp = $is_slashed ? stripslashes( $images['img_url'][ $index ] ) : $images['img_url'][ $index ];
76
 
77
+ $src = $tmp = strpos( $src, $this->upload_resource['content_path'] ) === 0 ? untrailingslashit( get_home_url() ) . $src : $src;
78
+
79
  if ( apply_filters( 'optml_ignore_image_link', false, $src ) ||
80
  false !== strpos( $src, Optml_Config::$service_url ) ||
81
  ! $this->can_replace_url( $src )
82
  ) {
83
+
84
  continue; // @codeCoverageIgnore
85
  }
86
 
87
+ $resize = apply_filters( 'optml_default_crop', array() );
88
+
89
  list( $width, $height, $resize ) = self::parse_dimensions_from_tag(
90
  $images['img_tag'][ $index ],
91
  $image_sizes,
96
  )
97
  );
98
  if ( false === $width && false === $height ) {
99
+ list( $width, $height, $crop ) = $this->parse_dimensions_from_filename( $tmp );
100
  }
 
101
  if ( empty( $resize ) && isset( $sizes2crop[ $width . $height ] ) ) {
102
  $resize = $this->to_optml_crop( $sizes2crop[ $width . $height ] );
103
+ } elseif ( isset( $crop ) ) {
104
+ $resize = $this->to_optml_crop( $crop );
105
  }
106
 
107
  $optml_args = [ 'width' => $width, 'height' => $height, 'resize' => $resize ];
153
  }
154
  if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $tag, $size ) ) {
155
  $size = array_pop( $size );
156
+
157
  if ( false === $args['width'] && false === $args['height'] && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
158
  $args['width'] = (int) $image_sizes[ $size ]['width'];
159
  $args['height'] = (int) $image_sizes[ $size ]['height'];
161
  if ( 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
162
  $args['resize'] = $this->to_optml_crop( $image_sizes[ $size ]['crop'] );
163
  }
164
+ } else {
165
+ $args['resize'] = apply_filters( 'optml_parse_resize_from_tag', [], $tag );
166
  }
167
 
168
  return array( $args['width'], $args['height'], $args['resize'] );
204
  return $sources;
205
  }
206
  $original_url = null;
207
+ $cropping = null;
208
  if ( count( $size_array ) === 2 ) {
209
  $sizes = self::size_to_crop();
210
  $cropping = isset( $sizes[ $size_array[0] . $size_array[1] ] ) ? $this->to_optml_crop( $sizes[ $size_array[0] . $size_array[1] ] ) : null;
211
  }
212
+
213
  foreach ( $sources as $i => $source ) {
214
  $url = $source['url'];
215
+ list( $width, $height, $file_crop ) = $this->parse_dimensions_from_filename( $url );
216
 
217
  if ( empty( $width ) ) {
218
  $width = $image_meta['width'];
221
  if ( empty( $height ) ) {
222
  $height = $image_meta['height'];
223
  }
224
+
225
  if ( $original_url === null ) {
226
  if ( ! empty( $attachment_id ) ) {
227
  $original_url = wp_get_attachment_url( $attachment_id );
240
  }
241
  if ( $cropping !== null ) {
242
  $args['resize'] = $cropping;
243
+ } else {
244
+ $args['resize'] = $this->to_optml_crop( $file_crop );
245
  }
246
  $sources[ $i ]['url'] = apply_filters( 'optml_content_url', $original_url, $args );
247
  }
inc/url_replacer.php CHANGED
@@ -28,24 +28,88 @@ final class Optml_Url_Replacer extends Optml_App_Replacer {
28
  * @return Optml_Url_Replacer
29
  */
30
  public static function instance() {
31
- if ( is_null( self::$instance ) ) {
32
  self::$instance = new self();
33
- add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
34
  }
35
 
36
  return self::$instance;
37
  }
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * The initialize method.
41
  */
42
  public function init() {
43
 
44
  add_filter( 'optml_replace_image', array( $this, 'build_image_url' ), 10, 2 );
45
-
46
- if ( ! parent::init() ) {
47
- return; // @codeCoverageIgnore
48
- }
49
 
50
  Optml_Quality::$default_quality = $this->to_accepted_quality( $this->settings->get_quality() );
51
  Optml_Image::$watermark = new Optml_Watermark( $this->settings->get_site_settings()['watermark'] );
@@ -83,6 +147,9 @@ final class Optml_Url_Replacer extends Optml_App_Replacer {
83
  if ( ! $this->can_replace_url( $url ) ) {
84
  return $url;
85
  }
 
 
 
86
  if ( ! $this->is_valid_mimetype_from_url( $url ) ) {
87
  return $url;
88
  }
@@ -101,7 +168,10 @@ final class Optml_Url_Replacer extends Optml_App_Replacer {
101
  $new_url = $this->strip_image_size_from_url( $url );
102
 
103
  if ( $new_url !== $url ) {
104
- list( $args['width'], $args['height'] ) = $this->parse_dimensions_from_filename( $url );
 
 
 
105
  $url = $new_url;
106
  }
107
  $args['width'] = (int) $args['width'];
@@ -114,7 +184,12 @@ final class Optml_Url_Replacer extends Optml_App_Replacer {
114
  $args['height'] = $args['height'] > $this->max_height ? $this->max_height : $args['height'];
115
  }
116
 
117
- $new_url = ( new Optml_Image( $url, $args ) )->get_url( $this->settings->use_lazyload() ? false : $this->is_allowed_site );
 
 
 
 
 
118
 
119
  return $is_slashed ? addcslashes( $new_url, '/' ) : $new_url;
120
  }
28
  * @return Optml_Url_Replacer
29
  */
30
  public static function instance() {
31
+ if ( null === self::$instance ) {
32
  self::$instance = new self();
33
+ add_action( 'optml_replacer_setup', array( self::$instance, 'init' ) );
34
  }
35
 
36
  return self::$instance;
37
  }
38
 
39
+
40
+ /**
41
+ * Handles the url replacement in options and theme mods.
42
+ */
43
+ public function filter_options_and_mods() {
44
+ /**
45
+ * `optml_imgcdn_options_with_url` is a filter that allows themes or plugins to select which option
46
+ * holds an url and needs an optimization.
47
+ */
48
+ $options_list = apply_filters(
49
+ 'optml_imgcdn_options_with_url',
50
+ array(
51
+ 'theme_mods_' . get_option( 'stylesheet' ),
52
+ 'theme_mods_' . get_option( 'template' ),
53
+ )
54
+ );
55
+
56
+ foreach ( $options_list as $option ) {
57
+ add_filter( "option_$option", array( $this, 'replace_option_url' ) );
58
+ }
59
+
60
+ }
61
+
62
+ /**
63
+ * A filter which turns a local url into an optimized CDN image url or an array of image urls.
64
+ *
65
+ * @param string $url The url which should be replaced.
66
+ *
67
+ * @return string Replaced url.
68
+ */
69
+ public function replace_option_url( $url ) {
70
+ if ( empty( $url ) ) {
71
+ return $url;
72
+ }
73
+ // $url might be an array or an json encoded array with urls.
74
+ if ( is_array( $url ) || filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
75
+ $array = $url;
76
+ $encoded = false;
77
+
78
+ // it might a json encoded array
79
+ if ( is_string( $url ) ) {
80
+ $array = json_decode( $url, true );
81
+ $encoded = true;
82
+ }
83
+
84
+ // in case there is an array, apply it recursively.
85
+ if ( is_array( $array ) ) {
86
+ foreach ( $array as $index => $value ) {
87
+ $array[ $index ] = $this->replace_option_url( $value );
88
+ }
89
+
90
+ if ( $encoded ) {
91
+ return json_encode( $array );
92
+ }
93
+
94
+ return $array;
95
+ }
96
+
97
+ if ( filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
98
+ return $url;
99
+ }
100
+ }
101
+
102
+ return apply_filters( 'optml_content_url', $url );
103
+ }
104
+
105
  /**
106
  * The initialize method.
107
  */
108
  public function init() {
109
 
110
  add_filter( 'optml_replace_image', array( $this, 'build_image_url' ), 10, 2 );
111
+ add_filter( 'init', array( $this, 'filter_options_and_mods' ) );
112
+ parent::init();
 
 
113
 
114
  Optml_Quality::$default_quality = $this->to_accepted_quality( $this->settings->get_quality() );
115
  Optml_Image::$watermark = new Optml_Watermark( $this->settings->get_site_settings()['watermark'] );
147
  if ( ! $this->can_replace_url( $url ) ) {
148
  return $url;
149
  }
150
+ // Remove any query strings that might affect conversion.
151
+ $url = strtok( $url, '?' );
152
+
153
  if ( ! $this->is_valid_mimetype_from_url( $url ) ) {
154
  return $url;
155
  }
168
  $new_url = $this->strip_image_size_from_url( $url );
169
 
170
  if ( $new_url !== $url ) {
171
+ list( $args['width'], $args['height'], $crop ) = $this->parse_dimensions_from_filename( $url );
172
+ if ( $crop ) {
173
+ $args['resize'] = $this->to_optml_crop( $crop );
174
+ }
175
  $url = $new_url;
176
  }
177
  $args['width'] = (int) $args['width'];
184
  $args['height'] = $args['height'] > $this->max_height ? $this->max_height : $args['height'];
185
  }
186
 
187
+ $new_url = ( new Optml_Image( $url, $args ) )->get_url(
188
+ [
189
+ 'signed' => $this->settings->use_lazyload() ? false : $this->is_allowed_site,
190
+ 'apply_watermark' => apply_filters( 'optml_apply_watermark_for', true, $url ),
191
+ ]
192
+ );
193
 
194
  return $is_slashed ? addcslashes( $new_url, '/' ) : $new_url;
195
  }
optimole-wp.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Image optimization service by Optimole
4
  * Description: Complete handling of your website images.
5
- * Version: 2.0.3
6
  * Author: Optimole
7
  * Author URI: https://optimole.com
8
  * License: GPL-2.0+
@@ -26,7 +26,7 @@ function optml_autoload( $class ) {
26
  if ( strpos( $class, $prefix ) !== 0 ) {
27
  return;
28
  }
29
- foreach ( array( '/inc/', '/inc/traits/', '/inc/image_properties/' ) as $folder ) {
30
  $file = str_replace( $prefix . '_', '', $class );
31
  $file = strtolower( $file );
32
  $file = dirname( __FILE__ ) . $folder . $file . '.php';
@@ -75,7 +75,7 @@ function optml() {
75
  define( 'OPTML_URL', plugin_dir_url( __FILE__ ) );
76
  define( 'OPTML_JS_CDN', 'd5jmkjjpb7yfg.cloudfront.net' );
77
  define( 'OPTML_PATH', plugin_dir_path( __FILE__ ) );
78
- define( 'OPTML_VERSION', '2.0.3' );
79
  define( 'OPTML_NAMESPACE', 'optml' );
80
  define( 'OPTML_BASEFILE', __FILE__ );
81
  // Fallback for old PHP versions when this constant is not defined.
2
  /**
3
  * Plugin Name: Image optimization service by Optimole
4
  * Description: Complete handling of your website images.
5
+ * Version: 2.0.4
6
  * Author: Optimole
7
  * Author URI: https://optimole.com
8
  * License: GPL-2.0+
26
  if ( strpos( $class, $prefix ) !== 0 ) {
27
  return;
28
  }
29
+ foreach ( array( '/inc/', '/inc/traits/', '/inc/image_properties/', '/inc/compatibilities/' ) as $folder ) {
30
  $file = str_replace( $prefix . '_', '', $class );
31
  $file = strtolower( $file );
32
  $file = dirname( __FILE__ ) . $folder . $file . '.php';
75
  define( 'OPTML_URL', plugin_dir_url( __FILE__ ) );
76
  define( 'OPTML_JS_CDN', 'd5jmkjjpb7yfg.cloudfront.net' );
77
  define( 'OPTML_PATH', plugin_dir_path( __FILE__ ) );
78
+ define( 'OPTML_VERSION', '2.0.4' );
79
  define( 'OPTML_NAMESPACE', 'optml' );
80
  define( 'OPTML_BASEFILE', __FILE__ );
81
  // Fallback for old PHP versions when this constant is not defined.
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: optimole
3
  Tags: image optimization, cdn, image compression, compress image, images, optimization, perfomance, photos
4
  Requires at least: 4.7
5
- Tested up to: 5.0
6
  Requires PHP: 5.4
7
  License: GPLv3
8
  License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
@@ -91,6 +91,26 @@ Premium users will be able to optimize 10GB images per month with a 50GB viewing
91
 
92
  == Changelog ==
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
95
 
96
  * **Bug Fixes**
2
  Contributors: optimole
3
  Tags: image optimization, cdn, image compression, compress image, images, optimization, perfomance, photos
4
  Requires at least: 4.7
5
+ Tested up to: 5.1
6
  Requires PHP: 5.4
7
  License: GPLv3
8
  License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
91
 
92
  == Changelog ==
93
 
94
+ #### [Version 2.0.4](https://github.com/Codeinwp/optimole-wp/compare/v2.0.3...v2.0.4) (2019-03-11)
95
+
96
+ * **Bug Fixes**
97
+ * adds full compatibility with Envira gallery ([7fd618f](https://github.com/Codeinwp/optimole-wp/commit/7fd618f))
98
+ * compatibility with Foogallery plugin when the gallery uses lazyload too ([67991dc](https://github.com/Codeinwp/optimole-wp/commit/67991dc))
99
+ * compatibility with images which contains query arguments, causing broken image urls ([56108be](https://github.com/Codeinwp/optimole-wp/commit/56108be))
100
+ * compatibility with relative image urls ([8089610](https://github.com/Codeinwp/optimole-wp/commit/8089610))
101
+ * compatibility with Revolution slider, adds support for background images lazyload and exact match ([0bbd254](https://github.com/Codeinwp/optimole-wp/commit/0bbd254))
102
+ * compatibility with shortcode ultimate plugin ([164ba35](https://github.com/Codeinwp/optimole-wp/commit/164ba35))
103
+ * compatibility with Woocommerce, solving issue with zoom image on single product pages ([1692e2b](https://github.com/Codeinwp/optimole-wp/commit/1692e2b))
104
+ * image replacement on WordPress REST api responses ([24d191b](https://github.com/Codeinwp/optimole-wp/commit/24d191b))
105
+ * image url replacement on custom WordPress directory structure, fixes [#79](https://github.com/Codeinwp/optimole-wp/issues/79), thanks [@hackles](https://github.com/hackles) for reporting ([980fcef](https://github.com/Codeinwp/optimole-wp/commit/980fcef))
106
+
107
+ * **Features**
108
+ * tested up compatibility with WordPress 5.1 ([12726b6](https://github.com/Codeinwp/optimole-wp/commit/12726b6))
109
+ * **api:** adds filter for restricting watermark based on image source urls ([337d7fa](https://github.com/Codeinwp/optimole-wp/commit/337d7fa))
110
+ * **api:** adds filter to disable image replacement on a specific page/ur ([3250a8d](https://github.com/Codeinwp/optimole-wp/commit/3250a8d))
111
+
112
+
113
+
114
  #### [Version 2.0.3](https://github.com/Codeinwp/optimole-wp/compare/v2.0.2...v2.0.3) (2019-02-13)
115
 
116
  * **Bug Fixes**
themeisle-hash.json CHANGED
@@ -1 +1 @@
1
- {"optimole-wp.php":"eec35058fe695c524bad4c3ac6522e13"}
1
+ {"optimole-wp.php":"ee446ee3680afc37f3935c414c20e3da"}
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit91e3c305c500afd7731152212c1c7f2f::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInita736db24c5967be69c4f5a7bf289fe2f::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInita736db24c5967be69c4f5a7bf289fe2f
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInita736db24c5967be69c4f5a7bf289fe2f::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequirea736db24c5967be69c4f5a7bf289fe2f($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequirea736db24c5967be69c4f5a7bf289fe2f($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit91e3c305c500afd7731152212c1c7f2f
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit91e3c305c500afd7731152212c1c7f2f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit91e3c305c500afd7731152212c1c7f2f', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit91e3c305c500afd7731152212c1c7f2f::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit91e3c305c500afd7731152212c1c7f2f::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire91e3c305c500afd7731152212c1c7f2f($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire91e3c305c500afd7731152212c1c7f2f($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInita736db24c5967be69c4f5a7bf289fe2f
8
  {
9
  public static $files = array (
10
  '9fef4034ed73e26a337d9856ea126f7f' => __DIR__ . '/..' . '/codeinwp/themeisle-sdk/load.php',
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit91e3c305c500afd7731152212c1c7f2f
8
  {
9
  public static $files = array (
10
  '9fef4034ed73e26a337d9856ea126f7f' => __DIR__ . '/..' . '/codeinwp/themeisle-sdk/load.php',