PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 3.6.13
TinyPNG – JPEG, PNG & WebP image compression v3.6.13
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 5 months ago config 5 months ago css 5 months ago data 3 years ago images 3 years ago js 5 months ago vendor 4 months ago views 2 months ago class-tiny-apache-rewrite.php 2 months ago class-tiny-bulk-optimization.php 5 months ago class-tiny-cli.php 5 months ago class-tiny-compress-client.php 5 months ago class-tiny-compress-fopen.php 5 months ago class-tiny-compress.php 5 months ago class-tiny-conversion.php 2 months ago class-tiny-diagnostics.php 5 months ago class-tiny-exception.php 5 months ago class-tiny-helpers.php 5 months ago class-tiny-image-size.php 5 months ago class-tiny-image.php 5 months ago class-tiny-logger.php 2 months ago class-tiny-notices.php 2 months ago class-tiny-php.php 5 months ago class-tiny-picture.php 4 months ago class-tiny-plugin.php 2 months ago class-tiny-settings.php 2 months ago class-tiny-source-base.php 2 months ago class-tiny-source-image.php 5 months ago class-tiny-source-picture.php 5 months ago class-tiny-wp-base.php 5 months ago
class-tiny-picture.php
212 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 ( Tiny_Helpers::is_pagebuilder_request() ) {
69 return;
70 }
71
72 add_action( 'template_redirect', array( $this, 'on_template_redirect' ) );
73 }
74
75 public function on_template_redirect() {
76 $conversion_enabled = $this->settings->get_conversion_enabled();
77 if ( apply_filters( 'tiny_replace_with_picture', $conversion_enabled ) ) {
78 /**
79 * Controls wether the page should replace <img> with <picture> elements
80 * converted sources.
81 *
82 * @since 3.6.9
83 */
84 ob_start( array( $this, 'replace_sources' ), 1000 );
85 }
86 }
87
88 public function replace_sources( $content ) {
89 $content = $this->replace_picture_sources( $content );
90 $content = $this->replace_img_sources( $content );
91
92 return $content;
93 }
94
95 /**
96 * Will extend existing picture elements with additional sourcesets
97 *
98 * @param string $content
99 * @return string the new source html
100 */
101 private function replace_picture_sources( $content ) {
102 $picture_sources = $this->filter_pictures( $content );
103 foreach ( $picture_sources as $picture_source ) {
104 $content = $this->replace_picture( $content, $picture_source );
105 }
106 return $content;
107 }
108
109 private function replace_img_sources( $content ) {
110 $image_sources = $this->filter_images( $content );
111 foreach ( $image_sources as $image_source ) {
112 $content = Tiny_Picture::replace_image( $content, $image_source );
113 }
114 return $content;
115 }
116
117 /**
118 * Will search for all picture elements within the given source html
119 *
120 * @param string $content
121 * @return array<Tiny_Source_Picture> an array of picture element sources
122 */
123 private function filter_pictures( $content ) {
124 $matches = array();
125 if ( ! preg_match_all(
126 '#<picture\b[^>]*>.*?<\/picture>#is',
127 $content,
128 $matches
129 ) ) {
130 return array();
131 }
132
133 $pictures = array();
134 foreach ( $matches[0] as $raw_picture ) {
135 $pictures[] = new Tiny_Source_Picture(
136 $raw_picture,
137 $this->base_dir,
138 $this->allowed_domains
139 );
140 }
141
142 return $pictures;
143 }
144
145 /**
146 * Will add additional sourcesets to picture elements.
147 *
148 * @param string $content the full page content
149 * @param Tiny_Source_Picture $source the picture element
150 *
151 * @return string the updated content including augmented picture elements
152 */
153 private function replace_picture( $content, $source ) {
154 $content = str_replace( $source->raw_html, $source->augment_picture_element(), $content );
155 return $content;
156 }
157
158
159 /**
160 * Will replace img elements with picture elements that (possibly) have additional formats.
161 *
162 * @param string $content the full page content
163 * @param Tiny_Source_Image $source the picture element
164 *
165 * @return string the updated content including augmented picture elements
166 */
167 private static function replace_image( $content, $source ) {
168 $content = str_replace( $source->raw_html, $source->create_picture_elements(), $content );
169 return $content;
170 }
171
172 /**
173 * Filters out all images from the content and returns them as an array.
174 *
175 * @return Tiny_Image[]
176 */
177 private function filter_images( $content ) {
178 // Extract only the <body>...</body> section.
179 if ( preg_match( '/(?=<body).*<\/body>/is', $content, $body ) ) {
180 $content = $body[0];
181 }
182
183 // strip HTML comments.
184 $content = preg_replace( '/<!--(.*)-->/Uis', '', $content );
185
186 // strip existing <picture> blocks to avoid double-processing.
187 $content = preg_replace( '/<picture\b.*?>.*?<\/picture>/is', '', $content );
188
189 // Strip <noscript> blocks to avoid altering their contents.
190 $content = preg_replace( '/<noscript\b.*?>.*?<\/noscript>/is', '', $content );
191
192 // Find all <img> tags with any attributes.
193 if ( ! preg_match_all( '/<img\b[^>]*>/is', $content, $matches ) ) {
194 return array();
195 }
196 $images = array();
197 foreach ( $matches[0] as $img ) {
198 // Skip images without src or srcset
199 if ( ! preg_match( '/\b(?:src|srcset)\s*=/i', $img ) ) {
200 continue;
201 }
202 $images[] = new Tiny_Source_Image(
203 $img,
204 $this->base_dir,
205 $this->allowed_domains
206 );
207 }
208
209 return $images;
210 }
211 }
212