PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.3.9.1
Pods – Custom Content Types and Fields v3.3.9.1
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 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.3.8 3.3.9
pods / classes / fields / oembed.php
pods / classes / fields Last commit date
avatar.php 2 weeks ago boolean.php 2 weeks ago code.php 2 weeks ago color.php 2 weeks ago comment.php 2 weeks ago currency.php 2 weeks ago date.php 2 weeks ago datetime.php 2 weeks ago email.php 2 weeks ago file.php 2 weeks ago heading.php 2 weeks ago html.php 2 weeks ago link.php 2 weeks ago number.php 2 weeks ago oembed.php 2 weeks ago paragraph.php 2 weeks ago password.php 2 weeks ago phone.php 2 weeks ago pick.php 2 weeks ago slug.php 2 weeks ago taxonomy.php 2 weeks ago text.php 2 weeks ago time.php 2 weeks ago website.php 2 weeks ago wysiwyg.php 2 weeks ago
oembed.php
541 lines
1 <?php
2
3 // Don't load directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 die( '-1' );
6 }
7
8 /**
9 * @package Pods\Fields
10 */
11 class PodsField_OEmbed extends PodsField {
12
13 /**
14 * {@inheritdoc}
15 */
16 public static $group = 'Relationships / Media';
17
18 /**
19 * {@inheritdoc}
20 */
21 public static $type = 'oembed';
22
23 /**
24 * {@inheritdoc}
25 */
26 public static $label = 'oEmbed';
27
28 /**
29 * {@inheritdoc}
30 */
31 public static $prepare = '%s';
32
33 /**
34 * Available oEmbed providers
35 *
36 * @var array
37 * @since 2.7.0
38 */
39 private $providers = [];
40
41 /**
42 * Current embed width
43 *
44 * @var int
45 * @since 2.7.0
46 */
47 private $width = 0;
48
49 /**
50 * Current embed height
51 *
52 * @var int
53 * @since 2.7.0
54 */
55 private $height = 0;
56
57 /**
58 * {@inheritdoc}
59 */
60 public function setup() {
61
62 static::$group = __( 'Relationships / Media', 'pods' );
63 static::$label = __( 'oEmbed', 'pods' );
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function admin_init() {
70
71 // AJAX for Uploads
72 add_action( 'wp_ajax_oembed_update_preview', [ $this, 'admin_ajax_oembed_update_preview' ] );
73 }
74
75 /**
76 * {@inheritdoc}
77 */
78 public function options() {
79
80 $options = [
81 static::$type . '_width' => [
82 'label' => __( 'Embed Width', 'pods' ),
83 'default' => 0,
84 'type' => 'number',
85 'help' => __( 'Optional width to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ),
86 ],
87 static::$type . '_height' => [
88 'label' => __( 'Embed Height', 'pods' ),
89 'default' => 0,
90 'type' => 'number',
91 'help' => __( 'Optional height to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ),
92 ],
93 static::$type . '_show_preview' => [
94 'label' => __( 'Show preview', 'pods' ),
95 'default' => 0,
96 'type' => 'boolean',
97 ],
98 ];
99
100 // Get all unique provider host names
101 $unique_providers = [];
102 foreach ( $this->get_providers() as $provider ) {
103 if ( ! in_array( $provider['host'], $unique_providers, true ) ) {
104 $unique_providers[] = $provider['host'];
105 }
106 }
107 sort( $unique_providers );
108
109 // Only add the options if we have data
110 if ( ! empty( $unique_providers ) ) {
111 $options[ static::$type . '_restrict_providers' ] = [
112 'label' => __( 'Restrict to providers', 'pods' ),
113 'help' => __( 'Restrict input to specific WordPress oEmbed compatible providers.', 'pods' ),
114 'type' => 'boolean',
115 'default' => 0,
116 'dependency' => true,
117 ];
118 $options[ static::$type . '_enable_providers' ] = [
119 'label' => __( 'Select enabled providers', 'pods' ),
120 'type' => 'boolean_group',
121 'depends-on' => [ static::$type . '_restrict_providers' => true ],
122 'boolean_group' => [],
123 ];
124 // Add all the oEmbed providers
125 foreach ( $unique_providers as $provider ) {
126 $options[ static::$type . '_enable_providers' ]['boolean_group'][ static::$type . '_enabled_providers_' . tag_escape( $provider ) ] = [
127 'label' => $provider,
128 'type' => 'boolean',
129 'default' => 0,
130 ];
131 }
132 }//end if
133
134 return $options;
135 }
136
137 /**
138 * {@inheritdoc}
139 */
140 public function schema( $options = null ) {
141
142 $schema = 'LONGTEXT';
143
144 return $schema;
145 }
146
147 /**
148 * {@inheritdoc}
149 */
150 public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
151 $value = $this->pre_save( $value, $id, $name, $options, null, $pod );
152
153 $width = (int) pods_v( static::$type . '_width', $options );
154 $height = (int) pods_v( static::$type . '_height', $options );
155 $args = [];
156 if ( $width > 0 ) {
157 $args['width'] = $width;
158 }
159 if ( $height > 0 ) {
160 $args['height'] = $height;
161 }
162
163 return wp_oembed_get( $value, $args );
164 }
165
166 /**
167 * {@inheritdoc}
168 */
169 public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
170
171 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
172 $form_field_type = PodsForm::$field_type;
173
174 $value = $this->normalize_value_for_input( $value, $options );
175
176 if ( isset( $options['name'] ) && ! pods_permission( $options ) ) {
177 if ( pods_v_bool( 'read_only_restricted', $options ) ) {
178 $options['readonly'] = true;
179 } else {
180 return;
181 }
182 } elseif ( ! pods_has_permissions( $options ) ) {
183 if ( pods_v_bool( 'read_only', $options ) ) {
184 $options['readonly'] = true;
185 }
186 }
187
188 if ( ! empty( $options['disable_dfv'] ) ) {
189 return pods_view( PODS_DIR . 'ui/fields/oembed.php', compact( array_keys( get_defined_vars() ) ) );
190 }
191
192 $type = pods_v( 'type', $options, static::$type );
193
194 $args = compact( array_keys( get_defined_vars() ) );
195 $args = (object) $args;
196
197 $this->render_input_script( $args );
198 }
199
200 /**
201 * {@inheritdoc}
202 */
203 public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
204 $validate = parent::validate( $value, $name, $options, $fields, $pod, $id, $params );
205
206 $errors = [];
207
208 if ( is_array( $validate ) ) {
209 $errors = $validate;
210 }
211
212 $check = $this->pre_save( $value, $id, $name, $options, $fields, $pod, $params );
213
214 if ( is_array( $check ) ) {
215 $errors = $check;
216 } else {
217 if ( 0 < strlen( (string) $value ) && '' === $check ) {
218 if ( $this->is_required( $options ) ) {
219 $errors[] = __( 'This field is required.', 'pods' );
220 }
221 }
222 }
223
224 if ( ! empty( $errors ) ) {
225 return $errors;
226 }
227
228 return $validate;
229 }
230
231 /**
232 * {@inheritdoc}
233 */
234 public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
235 $value = $this->strip_html( $value, $options );
236 $value = $this->strip_shortcodes( $value, $options );
237 $value = $this->trim_whitespace( $value, $options );
238
239 // Only allow ONE URL
240 if ( ! empty( $value ) ) {
241 $value = explode( ' ', $value );
242 $value = esc_url( $value[0] );
243 }
244
245 if ( $this->validate_provider( $value, $options ) ) {
246 return $value;
247 } else {
248 return false;
249 }
250
251 }
252
253 /**
254 * {@inheritdoc}
255 */
256 public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
257
258 $value = $this->pre_save( $value, $id, $name, $options, $fields, $pod );
259
260 return $value;
261 }
262
263 /**
264 * {@inheritdoc}
265 */
266 public function strip_html( $value, $options = null ) {
267
268 if ( is_array( $value ) ) {
269 // @codingStandardsIgnoreLine
270 $value = @implode( ' ', $value );
271 }
272
273 $value = trim( $value );
274
275 if ( empty( $value ) ) {
276 return $value;
277 }
278
279 // Strip HTML
280 $value = wp_strip_all_tags( $value );
281
282 // Strip shortcodes
283 $value = strip_shortcodes( $value );
284
285 return $value;
286 }
287
288 /**
289 * Passes any unlinked URLs that are on their own line to {@link WP_Embed::shortcode()} for potential embedding.
290 *
291 * @see WP_Embed::autoembed()
292 * @see WP_Embed::autoembed_callback()
293 *
294 * @uses PodsField_OEmbed::autoembed_callback()
295 *
296 * @param string $content The content to be searched.
297 *
298 * @return string Potentially modified $content.
299 *
300 * @since 2.7.0
301 */
302 public function autoembed( $content ) {
303
304 // Replace line breaks from all HTML elements with placeholders.
305 $content = wp_replace_in_html_tags( $content, [ "\n" => '<!-- wp-line-break -->' ] );
306
307 // Find URLs that are on their own line.
308 $content = preg_replace_callback(
309 '|^(\s*)(https?://[^\s"]+)(\s*)$|im', [
310 $this,
311 'autoembed_callback',
312 ], $content
313 );
314
315 // Put the line breaks back.
316 return str_replace( '<!-- wp-line-break -->', "\n", $content );
317
318 }
319
320 /**
321 * Callback function for {@link WP_Embed::autoembed()}.
322 *
323 * @param array $match A regex match array.
324 *
325 * @return string The embed shortcode
326 *
327 * @since 2.7.0
328 */
329 public function autoembed_callback( $match ) {
330
331 $shortcode = '[embed width="' . $this->width . '" height="' . $this->height . '"]' . $match[2] . '[/embed]';
332
333 return $shortcode;
334
335 }
336
337 /**
338 * Get a list of available providers from the WP_oEmbed class
339 *
340 * @see wp-includes/class-oembed.php
341 * @return array $providers {
342 * Array of provider data with regex as key
343 *
344 * @type string URL for this provider
345 * @type int
346 * @type string Hostname for this provider
347 * }
348 *
349 * @since 2.7.0
350 */
351 public function get_providers() {
352
353 // Return class property if already set
354 if ( ! empty( $this->providers ) ) {
355 return $this->providers;
356 }
357
358 if ( ! class_exists( 'WP_oEmbed' ) && file_exists( ABSPATH . WPINC . '/class-oembed.php' ) ) {
359 require_once ABSPATH . WPINC . '/class-oembed.php';
360 }
361
362 // Return an empty array if no providers could be found
363 $providers = [];
364
365 if ( function_exists( '_wp_oembed_get_object' ) ) {
366 $wp_oembed = _wp_oembed_get_object();
367 $providers = $wp_oembed->providers;
368
369 foreach ( $providers as $key => $provider ) {
370 $url = wp_parse_url( $provider[0] );
371 $host = $url['host'];
372 $tmp = explode( '.', $host );
373
374 if ( count( $tmp ) === 3 ) {
375 // Take domain names like .co.uk in consideration
376 if ( ! in_array( 'co', $tmp, true ) ) {
377 unset( $tmp[0] );
378 }
379 } elseif ( count( $tmp ) === 4 ) {
380 // Take domain names like .co.uk in consideration
381 unset( $tmp[0] );
382 }
383
384 $host = implode( '.', $tmp );
385
386 $providers[ $key ]['host'] = $host;
387 }
388
389 $this->providers = $providers;
390 }//end if
391
392 return $providers;
393
394 }
395
396 /**
397 * Takes a URL and returns the corresponding oEmbed provider's URL, if there is one.
398 *
399 * @since 2.7.0
400 * @access public
401 *
402 * @see WP_oEmbed::get_provider()
403 *
404 * @param string $url The URL to the content.
405 * @param string|array $args Optional provider arguments.
406 *
407 * @return false|string False on failure, otherwise the oEmbed provider URL.
408 */
409 public function get_provider( $url, $args = [] ) {
410
411 if ( ! class_exists( 'WP_oEmbed' ) && file_exists( ABSPATH . WPINC . '/class-oembed.php' ) ) {
412 require_once ABSPATH . WPINC . '/class-oembed.php';
413 }
414
415 if ( function_exists( '_wp_oembed_get_object' ) ) {
416 $wp_oembed = _wp_oembed_get_object();
417
418 if ( is_callable( [ $wp_oembed, 'get_provider' ] ) ) {
419 return $wp_oembed->get_provider( $url, $args );
420 }
421 }
422
423 return false;
424 }
425
426 /**
427 * Validate a value with the enabled oEmbed providers (if required).
428 *
429 * @since 2.7.0
430 *
431 * @param string $value Field value.
432 * @param array $options Field options.
433 *
434 * @return bool
435 */
436 public function validate_provider( $value, $options ) {
437
438 // Check if we need to validate.
439 if ( 0 === (int) pods_v( static::$type . '_restrict_providers', $options ) ) {
440 return true;
441 }
442
443 $providers = $this->get_providers();
444
445 // Filter existing providers.
446 foreach ( $providers as $key => $provider ) {
447 $fieldname = static::$type . '_enabled_providers_' . tag_escape( $provider['host'] );
448
449 /**
450 * @todo Future compat to enable serialised strings as field options
451 */
452
453 /**
454 * Current solution: all separate field options.
455 */
456 if ( empty( $options[ $fieldname ] ) ) {
457 unset( $providers[ $key ] );
458 }
459 }
460
461 // Value validation.
462 $provider_match = $this->get_provider( $value );
463
464 foreach ( $providers as $match => $provider ) {
465 if ( $provider_match === $match ) {
466 return true;
467 }
468 }
469
470 return false;
471 }
472
473 /**
474 * Handle update preview AJAX.
475 *
476 * @since 2.7.0
477 */
478 public function admin_ajax_oembed_update_preview() {
479
480 // Sanitize input.
481 // @codingStandardsIgnoreLine
482 $params = pods_unslash( (array) $_POST );
483
484 if ( ! empty( $params['_nonce_pods_oembed'] ) && ! empty( $params['pods_field_oembed_value'] ) && wp_verify_nonce( $params['_nonce_pods_oembed'], 'pods_field_oembed_preview' ) ) {
485 /**
486 * Filter the capability required to generate an oEmbed preview. Generating a preview triggers a server-side fetch, so it can be gated behind a capability by default. Set to a different capability, or an empty/false value, to only require the nonce (e.g. for front-end forms).
487 *
488 * @since 3.3.9.1
489 * @param string|null $capability The capability required. Default off.
490 */
491 $preview_capability = apply_filters( 'pods_field_oembed_preview_capability', null );
492
493 if ( $preview_capability && ! current_user_can( $preview_capability ) ) {
494 wp_send_json_error( __( 'Unauthorized request', 'pods' ) );
495 }
496
497 $name = '';
498 $value = '';
499 $options = [];
500
501 if ( ! empty( $params['pods_field_oembed_name'] ) ) {
502 $name = $params['pods_field_oembed_name'];
503 }
504
505 if ( ! empty( $params['pods_field_oembed_value'] ) ) {
506 $value = $params['pods_field_oembed_value'];
507 $value = $this->strip_html( $value );
508 $value = $this->strip_shortcodes( $value );
509 $value = $this->trim_whitespace( $value );
510 }
511
512 if ( ! empty( $params['pods_field_oembed_options'] ) ) {
513 $options = $params['pods_field_oembed_options'];
514 }
515
516 // Load the field to get it's options.
517 $options = pods_api()->load_field( $options );
518
519 // Field options are stored here, if not, just stay with the full options array.
520 if ( ! empty( $options['options'] ) ) {
521 $options = $options['options'];
522 }
523
524 // Run display function to run oEmbed.
525 $value = $this->display( $value, $name, $options );
526
527 if ( empty( $value ) ) {
528 $value = __( 'Please choose a valid oEmbed URL.', 'pods' );
529 wp_send_json_error( $value );
530 } else {
531 wp_send_json_success( $value );
532 }
533 }//end if
534 wp_send_json_error( __( 'Unauthorized request', 'pods' ) );
535
536 die();
537 // Kill it!
538 }
539
540 }
541