PluginProbe
Embed Privacy / 1.10.7
Embed Privacy v1.10.7
1.14.0 1.13.0 trunk 0.1 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.10.0 1.10.1 1.10.10 1.10.2 1.10.3 1.10.4 1.10.5 1.10.6 1.10.7 1.10.8 1.10.9 1.11.0 1.11.1 1.11.2 All 68 releases
embed-privacy / inc / data / class-replacer.php

class-replacer.php in Embed Privacy 1.10.7, at inc/data/class-replacer.php

233 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace epiphyt\Embed_Privacy\data;
3
4 use epiphyt\Embed_Privacy\embed\Replacement;
5 use epiphyt\Embed_Privacy\Embed_Privacy;
6 use epiphyt\Embed_Privacy\handler\Oembed;
7 use epiphyt\Embed_Privacy\integration\X;
8
9 /**
10 * Replacer functionality.
11 *
12 * @author Epiphyt
13 * @license GPL2
14 * @package epiphyt\Embed_Privacy
15 * @since 1.10.0
16 */
17 final class Replacer {
18 /**
19 * Extend a regular expression pattern with certain tags.
20 *
21 * @param string $pattern Pattern to extend
22 * @param \epiphyt\Embed_privacy\embed\Provider|null $provider Current embed provider
23 * @return string Extended pattern
24 */
25 public static function extend_pattern( $pattern, $provider ) {
26 if ( empty( $pattern ) ) {
27 return $pattern;
28 }
29
30 if ( \str_contains( $pattern, '<' ) && \str_contains( $pattern, '>' ) ) {
31 return $pattern;
32 }
33
34 $allowed_tags = [
35 'blockquote',
36 'div',
37 'embed',
38 'iframe',
39 'object',
40 ];
41
42 /**
43 * Filter allowed HTML tags in regular expressions.
44 * Only elements matching these tags get processed.
45 *
46 * @deprecated 1.10.0 Use embed_privacy_replacer_matcher_elements instead
47 * @since 1.6.0
48 *
49 * @param string[] $allowed_tags The allowed tags
50 * @param string $provider_name The embed provider without spaces and in lowercase
51 * @return array A list of allowed tags
52 */
53 $allowed_tags = \apply_filters_deprecated(
54 'embed_privacy_matcher_elements',
55 [
56 $allowed_tags,
57 $provider->get_name(),
58 ],
59 '1.10.0',
60 'embed_privacy_replacer_matcher_elements'
61 );
62
63 /**
64 * Filter allowed HTML tags in regular expressions.
65 * Only elements matching these tags get processed.
66 *
67 * @since 1.10.0
68 *
69 * @param string[] $allowed_tags List of allowed tags
70 * @param \epiphyt\Embed_privacy\embed\Provider|null $provider Embed provider
71 * @return array Updated list of allowed tags
72 */
73 $allowed_tags = (array) \apply_filters( 'embed_privacy_replacer_matcher_elements', $allowed_tags, $provider );
74
75 $tags_regex = '(' . \implode( '|', \array_filter( $allowed_tags, static function( $tag ) {
76 return \preg_quote( $tag, '/' );
77 } ) ) . ')';
78 $pattern = '/<' . $tags_regex . '([^"]*)"([^<]*)(?<original_pattern>' . \trim( $pattern, '/' ) . ')([^"]*)"([^>]*)(>(.*?)<\/' . $tags_regex . ')?>/';
79
80 return $pattern;
81 }
82
83 /**
84 * Replace embeds with a container and hide the embed with an HTML comment.
85 *
86 * @param string $content The original content
87 * @param string $tag The shortcode tag if called via do_shortcode
88 * @return string The updated content
89 */
90 public static function replace_embeds( $content, $tag = '' ) {
91 $embed_privacy = Embed_Privacy::get_instance();
92
93 // do nothing in admin
94 if ( ! $embed_privacy->use_cache ) {
95 return $content;
96 }
97
98 if ( $embed_privacy->is_ignored_request ) {
99 return $content;
100 }
101
102 // do nothing for ignored shortcodes
103 if ( ! empty( $tag ) && \in_array( $tag, $embed_privacy->shortcode->get_ignored(), true ) ) {
104 return $content;
105 }
106
107 // check content for already available embeds
108 if ( ! $embed_privacy->has_embed && \str_contains( $content, '<div class="embed-privacy-overlay">' ) ) {
109 $embed_privacy->has_embed = true;
110 }
111
112 $new_content = $content;
113 $replacement = new Replacement( $new_content );
114 $new_content = $replacement->get();
115
116 while ( $new_content !== $content ) {
117 $content = $new_content;
118 $replacement = new Replacement( $new_content );
119 $new_content = $replacement->get();
120 }
121
122 return $new_content;
123 }
124
125 /**
126 * Replace oembed embeds with a container and hide the embed with an HTML comment.
127 *
128 * @param string $output The original output
129 * @param string $url The URL to the embed
130 * @param array $attributes Additional attributes of the embed
131 * @return string The updated embed code
132 */
133 public static function replace_oembed( $output, $url, array $attributes ) {
134 $embed_privacy = Embed_Privacy::get_instance();
135
136 // do nothing in admin
137 if ( ! $embed_privacy->use_cache ) {
138 return $output;
139 }
140
141 if ( $embed_privacy->is_ignored_request ) {
142 return $output;
143 }
144
145 // ignore embeds without host (ie. relative URLs)
146 if ( ! empty( $url ) && empty( \wp_parse_url( $url, \PHP_URL_HOST ) ) ) {
147 return $output;
148 }
149
150 // check the current host
151 // see: https://github.com/epiphyt/embed-privacy/issues/24
152 if ( \str_contains( $url, \wp_parse_url( \home_url(), \PHP_URL_HOST ) ) ) {
153 return $output;
154 }
155
156 $replacement = new Replacement( $output, $url );
157
158 foreach ( $replacement->get_providers() as $provider ) {
159 // make sure to only run once
160 if ( \str_contains( $output, 'data-embed-provider="' . $provider->get_name() . '"' ) ) {
161 return $output;
162 }
163
164 $embed_title = Oembed::get_title( $output );
165 /* translators: embed title */
166 $attributes['embed_title'] = ! empty( $embed_title ) ? $embed_title : '';
167 $attributes['embed_url'] = $url;
168 $attributes['is_oembed'] = true;
169 $attributes['strip_newlines'] = true;
170
171 // the default dimensions are useless
172 // so ignore them if recognized as such
173 $defaults = \wp_embed_defaults( $url );
174
175 if (
176 ! empty( $attributes['height'] ) && $attributes['height'] === $defaults['height']
177 && ! empty( $attributes['width'] ) && $attributes['width'] === $defaults['width']
178 ) {
179 unset( $attributes['height'], $attributes['width'] );
180
181 $dimensions = Oembed::get_dimensions( $output );
182
183 if ( ! empty( $dimensions ) ) {
184 $attributes = \array_merge( $attributes, $dimensions );
185 }
186 }
187
188 // check for local tweets
189 if ( $provider->is( 'x' ) && \get_option( 'embed_privacy_local_tweets' ) ) {
190 return X::get_local_tweet( $output );
191 }
192
193 $output = $replacement->get( $attributes, $provider );
194 }
195
196 return $output;
197 }
198
199 /**
200 * Replace video shortcode embeds.
201 *
202 * @param string $output Video shortcode HTML output
203 * @param array $attributes Array of video shortcode attributes
204 * @return string Updated embed code
205 */
206 public static function replace_video_shortcode( $output, array $attributes ) {
207 $url = isset( $attributes['src'] ) ? $attributes['src'] : '';
208
209 if ( empty( $url ) && ! empty( $attributes['mp4'] ) ) {
210 $url = $attributes['mp4'];
211 }
212 else if ( empty( $url ) && ! empty( $attributes['m4v'] ) ) {
213 $url = $attributes['m4v'];
214 }
215 else if ( empty( $url ) && ! empty( $attributes['webm'] ) ) {
216 $url = $attributes['webm'];
217 }
218 else if ( empty( $url ) && ! empty( $attributes['ogv'] ) ) {
219 $url = $attributes['ogv'];
220 }
221 else if ( empty( $url ) && ! empty( $attributes['flv'] ) ) {
222 $url = $attributes['flv'];
223 }
224
225 // ignore relative URLs
226 if ( empty( \wp_parse_url( $url, \PHP_URL_HOST ) ) ) {
227 return $output;
228 }
229
230 return self::replace_oembed( $output, $url, $attributes );
231 }
232 }
233