Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
04:56
created

PodsField_OEmbed::options()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 66
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 46
c 0
b 0
f 0
nc 6
nop 0
dl 0
loc 66
rs 8.6045

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package Pods\Fields
5
 */
6
class PodsField_OEmbed extends PodsField {
7
8
	/**
9
	 * {@inheritdoc}
10
	 */
11
	public static $group = 'Relationships / Media';
12
13
	/**
14
	 * {@inheritdoc}
15
	 */
16
	public static $type = 'oembed';
17
18
	/**
19
	 * {@inheritdoc}
20
	 */
21
	public static $label = 'oEmbed';
22
23
	/**
24
	 * {@inheritdoc}
25
	 */
26
	public static $prepare = '%s';
27
28
	/**
29
	 * Available oEmbed providers
30
	 *
31
	 * @var array
32
	 * @since 2.7
33
	 */
34
	private $providers = array();
35
36
	/**
37
	 * Current embed width
38
	 *
39
	 * @var int
40
	 * @since 2.7
41
	 */
42
	private $width = 0;
43
44
	/**
45
	 * Current embed height
46
	 *
47
	 * @var int
48
	 * @since 2.7
49
	 */
50
	private $height = 0;
51
52
	/**
53
	 * {@inheritdoc}
54
	 */
55
	public function setup() {
56
57
		self::$label = __( 'oEmbed', 'pods' );
58
	}
59
60
	/**
61
	 * {@inheritdoc}
62
	 */
63
	public function admin_init() {
64
65
		// AJAX for Uploads
66
		add_action( 'wp_ajax_oembed_update_preview', array( $this, 'admin_ajax_oembed_update_preview' ) );
67
	}
68
69
	/**
70
	 * {@inheritdoc}
71
	 */
72
	public function options() {
73
74
		$options = array(
75
			static::$type . '_repeatable'   => array(
76
				'label'             => __( 'Repeatable Field', 'pods' ),
77
				'default'           => 0,
78
				'type'              => 'boolean',
79
				'help'              => __( 'Making a field repeatable will add controls next to the field which allows users to Add/Remove/Reorder additional values. These values are saved in the database as an array, so searching and filtering by them may require further adjustments".', 'pods' ),
80
				'boolean_yes_label' => '',
81
				'dependency'        => true,
82
				'developer_mode'    => true,
83
			),
84
			static::$type . '_width'        => array(
85
				'label'   => __( 'Embed Width', 'pods' ),
86
				'default' => 0,
87
				'type'    => 'number',
88
				'help'    => __( 'Optional width to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ),
89
			),
90
			static::$type . '_height'       => array(
91
				'label'   => __( 'Embed Height', 'pods' ),
92
				'default' => 0,
93
				'type'    => 'number',
94
				'help'    => __( 'Optional height to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ),
95
			),
96
			static::$type . '_show_preview' => array(
97
				'label'   => __( 'Show preview', 'pods' ),
98
				'default' => 0,
99
				'type'    => 'boolean',
100
			),
101
		);
102
103
		// Get all unique provider host names
104
		$unique_providers = array();
105
		foreach ( $this->get_providers() as $provider ) {
106
			if ( ! in_array( $provider['host'], $unique_providers, true ) ) {
107
				$unique_providers[] = $provider['host'];
108
			}
109
		}
110
		sort( $unique_providers );
111
112
		// Only add the options if we have data
113
		if ( ! empty( $unique_providers ) ) {
114
			$options[ static::$type . '_restrict_providers' ] = array(
115
				'label'      => __( 'Restrict to providers', 'pods' ),
116
				'help'       => __( 'Restrict input to specific WordPress oEmbed compatible providers.', 'pods' ),
117
				'type'       => 'boolean',
118
				'default'    => 0,
119
				'dependency' => true,
120
			);
121
			$options[ static::$type . '_enable_providers' ]   = array(
122
				'label'      => __( 'Select enabled providers', 'pods' ),
123
				'depends-on' => array( static::$type . '_restrict_providers' => true ),
124
				'group'      => array(),
125
			);
126
			// Add all the oEmbed providers
127
			foreach ( $unique_providers as $provider ) {
128
				$options[ static::$type . '_enable_providers' ]['group'][ static::$type . '_enabled_providers_' . tag_escape( $provider ) ] = array(
129
					'label'   => $provider,
130
					'type'    => 'boolean',
131
					'default' => 0,
132
				);
133
			}
134
		}//end if
135
136
		return $options;
137
	}
138
139
	/**
140
	 * {@inheritdoc}
141
	 */
142
	public function schema( $options = null ) {
143
144
		$schema = 'LONGTEXT';
145
146
		return $schema;
147
	}
148
149
	/**
150
	 * {@inheritdoc}
151
	 */
152
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
153
154
		$value = $this->pre_save( $value, $id, $name, $options, null, $pod );
155
156
		$width  = (int) pods_v( static::$type . '_width', $options );
157
		$height = (int) pods_v( static::$type . '_height', $options );
158
		$args   = array();
159
		if ( $width > 0 ) {
160
			$args['width'] = $width;
161
		}
162
		if ( $height > 0 ) {
163
			$args['height'] = $height;
164
		}
165
166
		$value = wp_oembed_get( $value, $args );
167
168
		return $value;
169
	}
170
171
	/**
172
	 * {@inheritdoc}
173
	 */
174 View Code Duplication
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
176
		$options         = (array) $options;
177
		$form_field_type = PodsForm::$field_type;
178
179
		if ( is_array( $value ) ) {
180
			$value = implode( ' ', $value );
181
		}
182
183
		if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
184
			if ( pods_v( 'read_only', $options, false ) ) {
185
				$options['readonly'] = true;
186
			} else {
187
				return;
188
			}
189
		} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
190
			$options['readonly'] = true;
191
		}
192
193
		pods_view( PODS_DIR . 'ui/fields/oembed.php', compact( array_keys( get_defined_vars() ) ) );
194
	}
195
196
	/**
197
	 * {@inheritdoc}
198
	 */
199 View Code Duplication
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
201
		$errors = array();
202
203
		$check = $this->pre_save( $value, $id, $name, $options, $fields, $pod, $params );
204
205
		if ( is_array( $check ) ) {
206
			$errors = $check;
207
		} else {
208
			if ( 0 < strlen( $value ) && '' === $check ) {
209
				if ( 1 === (int) pods_v( 'required', $options ) ) {
210
					$errors[] = __( 'This field is required.', 'pods' );
211
				}
212
			}
213
		}
214
215
		if ( ! empty( $errors ) ) {
216
			return $errors;
217
		}
218
219
		return true;
220
	}
221
222
	/**
223
	 * {@inheritdoc}
224
	 */
225
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
226
227
		$value = $this->strip_html( $value, $options );
228
229
		// Only allow ONE URL
230
		if ( ! empty( $value ) ) {
231
			$value = explode( ' ', $value );
232
			$value = esc_url( $value[0] );
233
		}
234
235
		if ( $this->validate_provider( $value, $options ) ) {
236
			return $value;
237
		} else {
238
			return false;
239
		}
240
241
	}
242
243
	/**
244
	 * {@inheritdoc}
245
	 */
246
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
247
248
		$value = $this->pre_save( $value, $id, $name, $options, $fields, $pod );
249
250
		return $value;
251
	}
252
253
	/**
254
	 * {@inheritdoc}
255
	 */
256
	public function strip_html( $value, $options = null ) {
257
258
		if ( is_array( $value ) ) {
259
			// @codingStandardsIgnoreLine
260
			$value = @implode( ' ', $value );
261
		}
262
263
		$value = trim( $value );
264
265
		if ( empty( $value ) ) {
266
			return $value;
267
		}
268
269
		// Strip HTML
270
		$value = strip_tags( $value );
271
272
		// Strip shortcodes
273
		$value = strip_shortcodes( $value );
274
275
		return $value;
276
	}
277
278
	/**
279
	 * Passes any unlinked URLs that are on their own line to {@link WP_Embed::shortcode()} for potential embedding.
280
	 *
281
	 * @see   WP_Embed::autoembed()
282
	 * @see   WP_Embed::autoembed_callback()
283
	 *
284
	 * @uses  PodsField_OEmbed::autoembed_callback()
285
	 *
286
	 * @param string $content The content to be searched.
287
	 *
288
	 * @return string Potentially modified $content.
289
	 *
290
	 * @since 2.7
291
	 */
292
	public function autoembed( $content ) {
293
294
		// Replace line breaks from all HTML elements with placeholders.
295
		$content = wp_replace_in_html_tags( $content, array( "\n" => '<!-- wp-line-break -->' ) );
296
297
		// Find URLs that are on their own line.
298
		$content = preg_replace_callback(
299
			'|^(\s*)(https?://[^\s"]+)(\s*)$|im', array(
300
				$this,
301
				'autoembed_callback',
302
			), $content
303
		);
304
305
		// Put the line breaks back.
306
		return str_replace( '<!-- wp-line-break -->', "\n", $content );
307
308
	}
309
310
	/**
311
	 * Callback function for {@link WP_Embed::autoembed()}.
312
	 *
313
	 * @param array $match A regex match array.
314
	 *
315
	 * @return string The embed shortcode
316
	 *
317
	 * @since 2.7
318
	 */
319
	public function autoembed_callback( $match ) {
320
321
		$shortcode = '[embed width="' . $this->width . '" height="' . $this->height . '"]' . $match[2] . '[/embed]';
322
323
		return $shortcode;
324
325
	}
326
327
	/**
328
	 * Get a list of available providers from the WP_oEmbed class
329
	 *
330
	 * @see   wp-includes/class-oembed.php
331
	 * @return array $providers {
332
	 *     Array of provider data with regex as key
333
	 *
334
	 * @type string URL for this provider
335
	 * @type int
336
	 * @type string Hostname for this provider
337
	 * }
338
	 *
339
	 * @since 2.7
340
	 */
341
	public function get_providers() {
342
343
		// Return class property if already set
344
		if ( ! empty( $this->providers ) ) {
345
			return $this->providers;
346
		}
347
348
		if ( file_exists( ABSPATH . WPINC . '/class-oembed.php' ) ) {
349
			require_once ABSPATH . WPINC . '/class-oembed.php';
350
		}
351
352
		// Return an empty array if no providers could be found
353
		$providers = array();
354
355
		if ( function_exists( '_wp_oembed_get_object' ) ) {
356
			$wp_oembed = _wp_oembed_get_object();
357
			$providers = $wp_oembed->providers;
358
359
			foreach ( $providers as $key => $provider ) {
360
				$url  = wp_parse_url( $provider[0] );
361
				$host = $url['host'];
362
				$tmp  = explode( '.', $host );
363
364
				if ( count( $tmp ) === 3 ) {
365
					// Take domain names like .co.uk in consideration
366
					if ( ! in_array( 'co', $tmp, true ) ) {
367
						unset( $tmp[0] );
368
					}
369
				} elseif ( count( $tmp ) === 4 ) {
370
					// Take domain names like .co.uk in consideration
371
					unset( $tmp[0] );
372
				}
373
374
				$host = implode( '.', $tmp );
375
376
				$providers[ $key ]['host'] = $host;
377
			}
378
379
			$this->providers = $providers;
380
		}//end if
381
382
		return $providers;
383
384
	}
385
386
	/**
387
	 * Takes a URL and returns the corresponding oEmbed provider's URL, if there is one.
388
	 * This function is ripped from WP since Pods has support from 3.8 and in the WP core this function is 4.0+
389
	 * We've stripped the autodiscover part from this function to keep it basic
390
	 *
391
	 * @since  2.7
392
	 * @access public
393
	 *
394
	 * @see    WP_oEmbed::get_provider()
395
	 *
396
	 * @param string $url The URL to the content.
397
	 *
398
	 * @return false|string False on failure, otherwise the oEmbed provider URL.
399
	 */
400
	public function get_provider( $url ) {
401
402
		$provider = false;
403
404
		foreach ( $this->providers as $matchmask => $data ) {
405
			if ( isset( $data['host'] ) ) {
406
				unset( $data['host'] );
407
			}
408
			reset( $data );
409
410
			list( $providerurl, $regex ) = $data;
411
412
			$match = $matchmask;
413
414
			// Turn the asterisk-type provider URLs into regex
415
			if ( ! $regex ) {
416
				$matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i';
417
				$matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask );
418
			}
419
420
			if ( preg_match( $matchmask, $url ) ) {
421
				$provider = $match;
422
423
				break;
424
			}
425
		}//end foreach
426
427
		return $provider;
428
	}
429
430
	/**
431
	 * Validate a value with the enabled oEmbed providers (if required).
432
	 *
433
	 * @since 2.7
434
	 *
435
	 * @param string $value   Field value.
436
	 * @param array  $options Field options.
437
	 *
438
	 * @return bool
439
	 */
440
	public function validate_provider( $value, $options ) {
441
442
		// Check if we need to validate.
443
		if ( 0 === (int) pods_v( static::$type . '_restrict_providers', $options ) ) {
444
			return true;
445
		}
446
447
		$providers = $this->get_providers();
448
449
		// Filter existing providers.
450
		foreach ( $providers as $key => $provider ) {
451
			$fieldname = static::$type . '_enabled_providers_' . tag_escape( $provider['host'] );
452
453
			/**
454
			 * @todo Future compat to enable serialised strings as field options
455
			 */
456
457
			/**
458
			 * Current solution: all separate field options.
459
			 */
460
			if ( empty( $options[ $fieldname ] ) ) {
461
				unset( $providers[ $key ] );
462
			}
463
		}
464
465
		// Value validation.
466
		$provider_match = $this->get_provider( $value );
467
468
		foreach ( $providers as $match => $provider ) {
469
			if ( $provider_match === $match ) {
470
				return true;
471
			}
472
		}
473
474
		return false;
475
	}
476
477
	/**
478
	 * Handle update preview AJAX.
479
	 *
480
	 * @since 2.7
481
	 */
482
	public function admin_ajax_oembed_update_preview() {
483
484
		// Sanitize input.
485
		// @codingStandardsIgnoreLine
486
		$params = pods_unslash( (array) $_POST );
487
488
		if ( ! empty( $params['_nonce_pods_oembed'] ) && ! empty( $params['pods_field_oembed_value'] ) && wp_verify_nonce( $params['_nonce_pods_oembed'], 'pods_field_oembed_preview' ) ) {
489
			$value   = $this->strip_html( $params['pods_field_oembed_value'] );
490
			$name    = ( ! empty( $params['pods_field_oembed_name'] ) ) ? $this->strip_html( $params['pods_field_oembed_name'] ) : '';
491
			$options = ( ! empty( $params['pods_field_oembed_options'] ) ) ? $params['pods_field_oembed_options'] : array();
492
493
			// Load the field to get it's options.
494
			$options = pods_api()->load_field( (object) $options );
495
496
			// Field options are stored here, if not, just stay with the full options array.
497
			if ( ! empty( $options['options'] ) ) {
498
				$options = $options['options'];
499
			}
500
501
			// Run display function to run oEmbed.
502
			$value = $this->display( $value, $name, $options );
503
504
			if ( empty( $value ) ) {
505
				$value = __( 'Please choose a valid oEmbed URL.', 'pods' );
506
				wp_send_json_error( $value );
507
			} else {
508
				wp_send_json_success( $value );
509
			}
510
		}//end if
511
		wp_send_json_error( __( 'Unauthorized request', 'pods' ) );
512
513
		die();
514
		// Kill it!
515
	}
516
517
}
518