PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 3.8.0
TinyPNG – JPEG, PNG & WebP image compression v3.8.0
3.8.0 3.7.0 3.6.14 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.6.0 1.7.0 1.7.1 1.7.2 2.0.0 2.0.1 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.0.0 3.0.1 3.1.0 3.2.0 3.2.1 3.3 3.4 3.4.1 3.4.2 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.6.0 3.6.1 3.6.10 3.6.11 3.6.12 3.6.13 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
tiny-compress-images / src / class-tiny-picture.php
tiny-compress-images / src Last commit date
compatibility 2 months ago config 2 months ago css 7 months ago data 4 years ago images 4 years ago js 1 week ago vendor 6 months ago views 1 week ago class-tiny-apache-rewrite.php 2 months ago class-tiny-bulk-optimization.php 2 months ago class-tiny-cli.php 2 months ago class-tiny-compress-client.php 1 week ago class-tiny-compress-fopen.php 2 months ago class-tiny-compress.php 1 week ago class-tiny-conversion.php 4 months ago class-tiny-diagnostics.php 7 months ago class-tiny-exception.php 7 months ago class-tiny-helpers.php 2 months ago class-tiny-image-size.php 1 week ago class-tiny-image.php 1 week ago class-tiny-logger.php 2 months ago class-tiny-migrate.php 2 months ago class-tiny-notices.php 2 months ago class-tiny-php.php 2 months ago class-tiny-picture.php 2 months ago class-tiny-plugin.php 1 week ago class-tiny-settings.php 1 week ago class-tiny-source-base.php 1 week ago class-tiny-source-image.php 7 months ago class-tiny-source-picture.php 7 months ago class-tiny-wp-base.php 2 months ago
class-tiny-picture.php
261 lines
1 <?php
2
3 /*
4 * Tiny Compress Images - WordPress plugin.
5 * Copyright (C) 2015-2018 Tinify B.V.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc., 51
19 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 require_once __DIR__ . '/class-tiny-source-base.php';
23 require_once __DIR__ . '/class-tiny-source-image.php';
24 require_once __DIR__ . '/class-tiny-source-picture.php';
25
26 /**
27 * Class responsible for parsing and modifying html to insert picture elements.
28 *
29 * 1) searches for <picture> elements or <img> elements
30 * 2) checks wether existing source has a modern alternative
31 * 3) augments or creates a picture element
32 * 4) replaces the original source with the source which includes the modern format
33 */
34 class Tiny_Picture extends Tiny_WP_Base {
35 /** @var string */
36 private $base_dir;
37
38 /** @var array */
39 private $allowed_domains = array();
40
41 /** @var Tiny_Settings */
42 private $settings;
43
44 /**
45 * Initialize the plugin.
46 *
47 * @param Tiny_Settings $settings Tinify Settings
48 * @param string $base_dir Absolute path (e.g. ABSPATH)
49 * @param array $domains List of allowed domain URLs
50 */
51 public function __construct( $settings, $base_dir = ABSPATH, $domains = array() ) {
52 $this->settings = $settings;
53 $this->base_dir = $base_dir;
54 $this->allowed_domains = $domains;
55
56 if ( is_admin() || is_customize_preview() ) {
57 return;
58 }
59
60 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
61 return;
62 }
63
64 if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
65 return;
66 }
67
68 if ( static::is_pagebuilder_request() ) {
69 return;
70 }
71
72 add_action( 'template_redirect', array( $this, 'on_template_redirect' ) );
73 }
74
75 /**
76 * Checks whether the current request originates from a page builder.
77 *
78 * Detects known page builder query parameters to prevent picture-element
79 * injection from interfering with builder previews.
80 *
81 * @since 3.6.5
82 *
83 * @return bool True if a page builder query parameter is present.
84 */
85 protected static function is_pagebuilder_request() {
86 $pagebuilder_keys = array(
87 'fl_builder', // Beaver Builder
88 'et_fb', // Divi Builder
89 'bricks', // Bricks Builder
90 'breakdance', // Breakdance Builder
91 'breakdance_browser', // Breakdance Builder
92 'ct_builder', // Oxygen Builder
93 'fb-edit', // Avada Live Builder
94 'builder', // Avada Live Builder
95 'spio_no_cdn', // Site Origin
96 'tatsu', // Tatsu Builder
97 'tve', // Thrive Architect
98 'tcbf', // Thrive Architect
99 );
100
101 foreach ( $pagebuilder_keys as $key ) {
102 if ( static::has_get_var( $key ) ) {
103 return true;
104 }
105 }
106
107 return false;
108 }
109
110 /**
111 * Checks whether a GET variable exists in the original request.
112 *
113 * Wraps filter_has_var() to allow overriding in tests via late static binding.
114 *
115 * @since 3.6.5
116 *
117 * @param string $key The query string key to check.
118 * @return bool True if the key exists in the original GET request.
119 */
120 protected static function has_get_var( $key ) {
121 return filter_has_var( INPUT_GET, $key );
122 }
123
124 public function on_template_redirect() {
125 $conversion_enabled = $this->settings->get_conversion_enabled();
126 if ( apply_filters( 'tiny_replace_with_picture', $conversion_enabled ) ) {
127 /**
128 * Controls wether the page should replace <img> with <picture> elements
129 * converted sources.
130 *
131 * @since 3.6.9
132 */
133 ob_start( array( $this, 'replace_sources' ), 1000 );
134 }
135 }
136
137 public function replace_sources( $content ) {
138 $content = $this->replace_picture_sources( $content );
139 $content = $this->replace_img_sources( $content );
140
141 return $content;
142 }
143
144 /**
145 * Will extend existing picture elements with additional sourcesets
146 *
147 * @param string $content
148 * @return string the new source html
149 */
150 private function replace_picture_sources( $content ) {
151 $picture_sources = $this->filter_pictures( $content );
152 foreach ( $picture_sources as $picture_source ) {
153 $content = $this->replace_picture( $content, $picture_source );
154 }
155 return $content;
156 }
157
158 private function replace_img_sources( $content ) {
159 $image_sources = $this->filter_images( $content );
160 foreach ( $image_sources as $image_source ) {
161 $content = self::replace_image( $content, $image_source );
162 }
163 return $content;
164 }
165
166 /**
167 * Will search for all picture elements within the given source html
168 *
169 * @param string $content
170 * @return array<Tiny_Source_Picture> an array of picture element sources
171 */
172 private function filter_pictures( $content ) {
173 $matches = array();
174 if ( ! preg_match_all(
175 '#<picture\b[^>]*>.*?<\/picture>#is',
176 $content,
177 $matches
178 ) ) {
179 return array();
180 }
181
182 $pictures = array();
183 foreach ( $matches[0] as $raw_picture ) {
184 $pictures[] = new Tiny_Source_Picture(
185 $raw_picture,
186 $this->base_dir,
187 $this->allowed_domains
188 );
189 }
190
191 return $pictures;
192 }
193
194 /**
195 * Will add additional sourcesets to picture elements.
196 *
197 * @param string $content the full page content
198 * @param Tiny_Source_Picture $source the picture element
199 *
200 * @return string the updated content including augmented picture elements
201 */
202 private function replace_picture( $content, $source ) {
203 $content = str_replace( $source->raw_html, $source->augment_picture_element(), $content );
204 return $content;
205 }
206
207
208 /**
209 * Will replace img elements with picture elements that (possibly) have additional formats.
210 *
211 * @param string $content the full page content
212 * @param Tiny_Source_Image $source the picture element
213 *
214 * @return string the updated content including augmented picture elements
215 */
216 private static function replace_image( $content, $source ) {
217 $content = str_replace( $source->raw_html, $source->create_picture_elements(), $content );
218 return $content;
219 }
220
221 /**
222 * Filters out all images from the content and returns them as an array.
223 *
224 * @return Tiny_Image[]
225 */
226 private function filter_images( $content ) {
227 // Extract only the <body>...</body> section.
228 if ( preg_match( '/(?=<body).*<\/body>/is', $content, $body ) ) {
229 $content = $body[0];
230 }
231
232 // strip HTML comments.
233 $content = preg_replace( '/<!--(.*)-->/Uis', '', $content );
234
235 // strip existing <picture> blocks to avoid double-processing.
236 $content = preg_replace( '/<picture\b.*?>.*?<\/picture>/is', '', $content );
237
238 // Strip <noscript> blocks to avoid altering their contents.
239 $content = preg_replace( '/<noscript\b.*?>.*?<\/noscript>/is', '', $content );
240
241 // Find all <img> tags with any attributes.
242 if ( ! preg_match_all( '/<img\b[^>]*>/is', $content, $matches ) ) {
243 return array();
244 }
245 $images = array();
246 foreach ( $matches[0] as $img ) {
247 // Skip images without src or srcset
248 if ( ! preg_match( '/\b(?:src|srcset)\s*=/i', $img ) ) {
249 continue;
250 }
251 $images[] = new Tiny_Source_Image(
252 $img,
253 $this->base_dir,
254 $this->allowed_domains
255 );
256 }
257
258 return $images;
259 }
260 }
261