PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 1.2.0
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v1.2.0
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Shortcode.php
embedpress / EmbedPress Last commit date
Ends 9 years ago Providers 9 years ago AutoLoader.php 9 years ago Disabler.php 9 years ago Loader.php 9 years ago Plugin.php 9 years ago Shortcode.php 9 years ago index.html 9 years ago
Shortcode.php
432 lines
1 <?php
2 namespace EmbedPress;
3
4 use \EmbedPress\Plugin;
5 use \Embera\Embera;
6 use \Embera\Formatter;
7
8 (defined('ABSPATH') && defined('EMBEDPRESS_IS_LOADED')) or die("No direct script access allowed.");
9
10 /**
11 * Entity responsible to handle the plugin's shortcode events and behaviors.
12 *
13 * @package EmbedPress
14 * @author PressShack <help@pressshack.com>
15 * @copyright Copyright (C) 2016 Open Source Training, LLC. All rights reserved.
16 * @license GPLv2 or later
17 * @since 1.0.0
18 */
19 class Shortcode
20 {
21 /**
22 * The WP_oEmbed class instance.
23 *
24 * @since 1.0.0
25 * @access private
26 * @static
27 *
28 * @var string $oEmbedInstance
29 */
30 private static $oEmbedInstance = null;
31
32 /**
33 * Register the plugin's shortcode into WordPress.
34 *
35 * @since 1.0.0
36 * @static
37 *
38 * @return void
39 */
40 public static function register()
41 {
42 // Register the new shortcode for embeds.
43 add_shortcode(EMBEDPRESS_SHORTCODE, array('\\EmbedPress\\Shortcode', 'do_shortcode'), 1);
44 }
45
46 /**
47 * Method that converts the plugin shortcoded-string into its complex content.
48 *
49 * @since 1.0.0
50 * @static
51 *
52 * @param array $attributes @TODO
53 * @param string $subject The given string
54 * @return string
55 */
56 public static function do_shortcode($attributes = array(), $subject = null)
57 {
58 $decodedSubject = self::parseContent($subject, true, $attributes);
59
60 return $decodedSubject;
61 }
62
63 /**
64 * Replace a given content with its embeded HTML code.
65 *
66 * @since 1.0.0
67 * @static
68 *
69 * @param string The raw content that will be replaced.
70 * @param boolean Optional. If true, new lines at the end of the embeded code are stripped.
71 * @return string
72 */
73 public static function parseContent($subject, $stripNewLine = false, $customAttributes = array())
74 {
75 if (!empty($subject)) {
76 if (empty($customAttributes)) {
77 $customAttributes = self::parseContentAttributesFromString($subject);
78 }
79
80 $content = preg_replace('/(\['. EMBEDPRESS_SHORTCODE .'(?:\]|.+?\])|\[\/'. EMBEDPRESS_SHORTCODE .'\])/i', "", $subject);
81
82 // Check if the WP_oEmbed class is loaded
83 if (!self::$oEmbedInstance) {
84 require_once ABSPATH .'wp-includes/class-oembed.php';
85
86 self::$oEmbedInstance = _wp_oembed_get_object();
87 }
88
89 $emberaInstanceSettings = array(
90 'params' => array()
91 );
92
93 $attributes = self::parseContentAttributes($customAttributes);
94 if (isset($attributes['width']) || isset($attributes['height'])) {
95 if (isset($attributes['width'])) {
96 $emberaInstanceSettings['params']['width'] = $attributes['width'];
97 unset($attributes['width']);
98 }
99
100 if (isset($attributes['height'])) {
101 $emberaInstanceSettings['params']['height'] = $attributes['height'];
102 unset($attributes['height']);
103 }
104 }
105
106 // Identify what service provider the shortcode's link belongs to
107 $serviceProvider = self::$oEmbedInstance->get_provider($content);
108
109 // Gather info about the shortcode's link
110 $urlData = self::$oEmbedInstance->fetch($serviceProvider, $content, $attributes);
111
112 // Transform all shortcode attributes into html form. I.e.: {foo: "joe"} -> foo="joe"
113 $attributesHtml = array();
114 foreach ($attributes as $attrName => $attrValue) {
115 $attributesHtml[] = $attrName .'="'. $attrValue .'"';
116 }
117
118 // Define the EmbedPress html template where the generated embed will be injected in
119 $embedTemplate = '<div '. implode(' ', $attributesHtml) .'>{html}</div>';
120
121 // Check if $content is a google shortened url and tries to extract from it which Google service it refers to.
122 if (preg_match('/http[s]?:\/\/goo\.gl\/(?:([a-z]+)\/)?[a-z0-9]+\/?$/i', $content, $matches)) {
123 // Fetch all headers from the short-url so we can know how to handle its original content depending on the service.
124 $headers = get_headers($content);
125
126 $supportedServicesHeadersPatterns = array(
127 'maps' => '/^Location:\s+(http[s]?:\/\/.+)$/i'
128 );
129
130 $service = strtolower(@$matches[1]);
131 // No specific service was found in the url.
132 if (empty($service)) {
133 // Let's try to guess which service the original url belongs to.
134 foreach ($headers as $header) {
135 // Check if the short-url reffers to a Google Maps url.
136 if (preg_match($supportedServicesHeadersPatterns['maps'], $header, $matches)) {
137 // Replace the shortened url with its original url.
138 $content = $matches[1];
139 break;
140 }
141 }
142 unset($header);
143 } else {
144 // Check if the Google service is supported atm.
145 if (isset($supportedServicesHeadersPatterns[$service])) {
146 // Tries to extract the url based on its headers.
147 $originalUrl = self::extractContentFromHeaderAsArray($supportedServicesHeadersPatterns[$service], $headers);
148 // Replace the shortened url with its original url if the specific header was found.
149 if (!empty($originalUrl)) {
150 $content = $originalUrl;
151 }
152 unset($originalUrl);
153 }
154 }
155 unset($service, $supportedServicesHeadersPatterns, $headers, $matches);
156 }
157
158 // Try to generate the embed using WP API
159 $parsedContent = self::$oEmbedInstance->get_html($content, $attributes);
160 if (!$parsedContent) {
161 // If the embed couldn't be generated, we'll try to use Embera's API
162 $emberaInstance = new Embera($emberaInstanceSettings);
163 // Add support to the user's custom service providers
164 $additionalServiceProviders = Plugin::getAdditionalServiceProviders();
165 if (!empty($additionalServiceProviders)) {
166 foreach ($additionalServiceProviders as $serviceProviderClassName => $serviceProviderUrls) {
167 self::addServiceProvider($serviceProviderClassName, $serviceProviderUrls, $emberaInstance);
168 }
169
170 unset($serviceProviderUrls, $serviceProviderClassName);
171 }
172
173 // Register the html template
174 $emberaFormaterInstance = new Formatter($emberaInstance, true);
175 $emberaFormaterInstance->setTemplate($embedTemplate);
176
177 // Try to generate the embed using Embera API
178 $parsedContent = $emberaFormaterInstance->transform($content);
179
180 unset($emberaFormaterInstance, $additionalServiceProviders, $emberaInstance);
181 } else {
182 // Inject the generated code inside the html template
183 $parsedContent = str_replace('{html}', $parsedContent, $embedTemplate);
184
185 // Replace all single quotes to double quotes. I.e: foo='joe' -> foo="joe"
186 $parsedContent = str_replace("'", '"', $parsedContent);
187
188 // Replace the flag `{provider_alias}` which is used by Embera with the "ose-<serviceProviderAlias>". I.e: YouTube -> "ose-youtube"
189 $parsedContent = preg_replace('/((?:ose-)?\{provider_alias\})/i', "ose-". strtolower($urlData->provider_name), $parsedContent);
190 }
191
192 unset($embedTemplate, $urlData, $serviceProvider);
193
194 // This assure that the iframe has the same dimensions the user wants to
195 if (isset($emberaInstanceSettings['params']['width']) || isset($emberaInstanceSettings['params']['height'])) {
196 if (isset($emberaInstanceSettings['params']['width']) && isset($emberaInstanceSettings['params']['height'])) {
197 $customWidth = (int)$emberaInstanceSettings['params']['width'];
198 $customHeight = (int)$emberaInstanceSettings['params']['height'];
199 } else {
200 preg_match_all('/\<iframe\s+width="(\d+)"\s+height="(\d+)"/i', $parsedContent, $matches);
201 $iframeWidth = (int)$matches[1][0];
202 $iframeHeight = (int)$matches[2][0];
203 $iframeRatio = ceil($iframeWidth / $iframeHeight);
204
205 if (isset($emberaInstanceSettings['params']['width'])) {
206 $customWidth = (int)$emberaInstanceSettings['params']['width'];
207 $customHeight = ceil($customWidth / $iframeRatio);
208 } else {
209 $customHeight = (int)$emberaInstanceSettings['params']['height'];
210 $customWidth = $iframeRatio * $customHeight;
211 }
212
213 unset($iframeRatio, $iframeHeight, $iframeWidth, $matches);
214 }
215
216 $parsedContent = preg_replace('/\s+width\=\"(\d+)\"/i', ' width="'. $customWidth .'"', $parsedContent);
217 $parsedContent = preg_replace('/\s+height\=\"(\d+)\"/i', ' height="'. $customHeight .'"', $parsedContent);
218 }
219
220 if ($stripNewLine) {
221 $parsedContent = preg_replace('/\n/', '', $parsedContent);
222 }
223
224 if (!empty($parsedContent)) {
225 return $parsedContent;
226 }
227 }
228
229 return $subject;
230 }
231
232 /**
233 * Method that adds support to a given new service provider (SP).
234 *
235 * @since 1.0.0
236 * @static
237 *
238 * @param string $className The new SP class name.
239 * @param string $reference The new SP reference name.
240 * @param \Embera\Embera $emberaInstance The embera's instance where the SP will be registered in.
241 * @return boolean
242 */
243 public static function addServiceProvider($className, $reference, &$emberaInstance)
244 {
245 if (empty($className) || empty($reference)) {
246 return false;
247 }
248
249 if (is_string($reference)) {
250 $emberaInstance->addProvider($reference, EMBEDPRESS_NAMESPACE ."\\Providers\\{$className}");
251 } else if (is_array($reference)) {
252 foreach ($reference as $serviceProviderUrl) {
253 self::addServiceProvider($className, $serviceProviderUrl, $emberaInstance);
254 }
255 } else {
256 return false;
257 }
258 }
259
260 /**
261 * Method that retrieves all custom parameters from a shortcoded string.
262 *
263 * @since 1.0.0
264 * @static
265 *
266 * @param string $subject The given shortcoded string.
267 * @return array
268 */
269 public static function parseContentAttributesFromString($subject)
270 {
271 $customAttributes = array();
272 if (preg_match('/\[embed\s*(.*?)\]/i', stripslashes($subject), $m)) {
273 if (preg_match_all('/(\!?\w+-?\w*)(?:="(.+?)")?/i', stripslashes($m[1]), $matches)) {
274 $attributes = $matches[1];
275 $attrValues = $matches[2];
276
277 foreach ($attributes as $attrIndex => $attrName) {
278 $customAttributes[$attrName] = $attrValues[$attrIndex];
279 }
280 }
281 }
282
283 return $customAttributes;
284 }
285
286 /**
287 * Method that parses and adds the "data-" prefix to the given custom shortcode attributes.
288 *
289 * @since 1.0.0
290 * @access private
291 * @static
292 *
293 * @param array $attributes The array containing the embed attributes.
294 * @return array
295 */
296 private static function parseContentAttributes(array $customAttributes)
297 {
298 $attributes = array(
299 'class' => array("embedpress-wrapper")
300 );
301
302 $embedShouldBeResponsive = true;
303 $embedShouldHaveCustomDimensions = false;
304 if (!empty($customAttributes)) {
305 if (isset($customAttributes['class'])) {
306 if (!empty($customAttributes['class'])) {
307 $customAttributes['class'] = explode(' ', $customAttributes['class']);
308
309 $attributes['class'] = array_merge($attributes['class'], $customAttributes['class']);
310 }
311
312 unset($customAttributes['class']);
313 }
314
315 if (isset($customAttributes['width'])) {
316 if (!empty($customAttributes['width'])) {
317 $attributes['width'] = (int)$customAttributes['width'];
318 $embedShouldHaveCustomDimensions = true;
319 }
320 }
321
322 if (isset($customAttributes['height'])) {
323 if (!empty($customAttributes['height'])) {
324 $attributes['height'] = (int)$customAttributes['height'];
325 $embedShouldHaveCustomDimensions = true;
326 }
327 }
328
329 if (!empty($customAttributes)) {
330 $attrNameDefaultPrefix = "data-";
331 foreach ($customAttributes as $attrName => $attrValue) {
332 if (is_numeric($attrName)) {
333 $attrName = $attrValue;
334 $attrValue = "";
335 }
336
337 $attrName = str_replace($attrNameDefaultPrefix, "", $attrName);
338
339 if (!strlen($attrValue)) {
340 if ($attrName[0] === "!") {
341 $attrValue = "false";
342 $attrName = substr($attrName, 1);
343 } else {
344 $attrValue = "true";
345 }
346 }
347
348 $attributes[$attrNameDefaultPrefix . $attrName] = $attrValue;
349 }
350 }
351
352 // Check if there's any "responsive" parameter
353 $responsiveAttributes = array("responsive", "data-responsive");
354 foreach ($responsiveAttributes as $responsiveAttr) {
355 if (isset($attributes[$responsiveAttr])) {
356 if (!strlen($attributes[$responsiveAttr])) { // If the parameter is passed but have no value, it will be true by default
357 $embedShouldBeResponsive = true;
358 } else {
359 $embedShouldBeResponsive = !self::valueIsFalse($attributes[$responsiveAttr]);
360 }
361
362 break;
363 }
364 }
365 unset($responsiveAttr, $responsiveAttributes);
366 }
367
368 if ($embedShouldBeResponsive && !$embedShouldHaveCustomDimensions) {
369 $attributes['class'][] = 'ose-{provider_alias} responsive';
370 } else {
371 $attributes['data-responsive'] = "false";
372 }
373
374 $attributes['class'] = implode(' ', array_unique(array_filter($attributes['class'])));
375
376 return $attributes;
377 }
378
379 /**
380 * Method that checks if a given value is/can be identified as (bool)false.
381 *
382 * @since 1.0.0
383 * @static
384 *
385 * @param mixed $subject The value to be checked.
386 * @return boolean
387 */
388 public static function valueIsFalse($subject)
389 {
390 $subject = strtolower(trim((string)$subject));
391 switch ($subject) {
392 case "0":
393 case "false":
394 case "off":
395 case "no":
396 case "n":
397 case "nil":
398 case "null":
399 return true;
400 default:
401 return false;
402 }
403 }
404
405 /**
406 * Return the value from a header which is in an array resulted from a get_headers() call.
407 * If the header cannot be found, this method will return null instead.
408 *
409 * @since 1.1.0
410 * @access private
411 * @static
412 *
413 * @param string $headerPattern Regex pattern the header and its value must match.
414 * @param array $headersList A list of headers resulted from a get_headers() call.
415 *
416 * @return mixed
417 */
418 private static function extractContentFromHeaderAsArray($headerPattern, $headersList)
419 {
420 $headerValue = null;
421
422 foreach ($headersList as $header) {
423 if (preg_match($headerPattern, $header, $matches)) {
424 $headerValue = $matches[1];
425 break;
426 }
427 }
428
429 return $headerValue;
430 }
431 }
432