PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / trunk
Pods – Custom Content Types and Fields vtrunk
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 / wysiwyg.php
pods / classes / fields Last commit date
avatar.php 4 months ago boolean.php 4 months ago code.php 4 months ago color.php 4 months ago comment.php 4 months ago currency.php 4 months ago date.php 4 months ago datetime.php 4 months ago email.php 4 months ago file.php 4 months ago heading.php 4 months ago html.php 4 months ago link.php 4 months ago number.php 4 months ago oembed.php 4 months ago paragraph.php 4 months ago password.php 4 months ago phone.php 4 months ago pick.php 4 months ago slug.php 4 months ago taxonomy.php 4 months ago text.php 4 months ago time.php 4 months ago website.php 4 months ago wysiwyg.php 4 months ago
wysiwyg.php
448 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_WYSIWYG extends PodsField {
12
13 /**
14 * {@inheritdoc}
15 */
16 public static $group = 'Paragraph';
17
18 /**
19 * {@inheritdoc}
20 */
21 public static $type = 'wysiwyg';
22
23 /**
24 * {@inheritdoc}
25 */
26 public static $label = 'WYSIWYG (Visual Editor)';
27
28 /**
29 * {@inheritdoc}
30 */
31 public static $prepare = '%s';
32
33 /**
34 * {@inheritdoc}
35 */
36 public function setup() {
37
38 static::$group = __( 'Paragraph', 'pods' );
39 static::$label = __( 'WYSIWYG (Visual Editor)', 'pods' );
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function options() {
46 $options = [
47 static::$type . '_editor' => [
48 'label' => __( 'Editor', 'pods' ),
49 'default' => 'tinymce',
50 'type' => 'pick',
51 'data' => apply_filters(
52 'pods_form_ui_field_wysiwyg_editors', [
53 'tinymce' => __( 'TinyMCE (WP Default, cannot be used with repeatable fields)', 'pods' ),
54 'quill' => __( 'Quill Editor (Limited line break functionality)', 'pods' ),
55 'cleditor' => __( 'CLEditor (No longer available, the fallback uses Quill Editor)', 'pods' ),
56 ]
57 ),
58 'pick_format_single' => 'dropdown',
59 'pick_show_select_text' => 0,
60 'dependency' => true,
61 ],
62 'editor_options' => [
63 'label' => __( 'Editor Options', 'pods' ),
64 'type' => 'boolean_group',
65 'depends-on' => [ static::$type . '_editor' => 'tinymce' ],
66 'boolean_group' => [
67 static::$type . '_media_buttons' => [
68 'label' => __( 'Enable Media Buttons', 'pods' ),
69 'default' => 1,
70 'type' => 'boolean',
71 ],
72 static::$type . '_delay_init' => [
73 'label' => __( 'Delay TinyMCE Initialization', 'pods' ),
74 'default' => 0,
75 'type' => 'boolean',
76 'help' => __( 'Delay the initialization of the TinyMCE editor until you click to initialize it.', 'pods' ),
77 ],
78 ],
79 ],
80 static::$type . '_editor_height' => [
81 'label' => __( 'Editor Height', 'pods' ),
82 'help' => __( 'Height in pixels', 'pods' ),
83 'default' => '',
84 'type' => 'number',
85 'depends-on' => [ static::$type . '_editor' => 'tinymce' ],
86 'number_decimals' => 0,
87 ],
88 'output_options' => [
89 'label' => __( 'Output Options', 'pods' ),
90 'type' => 'boolean_group',
91 'boolean_group' => [
92 static::$type . '_trim' => [
93 'label' => __( 'Trim extra whitespace before/after contents', 'pods' ),
94 'default' => 1,
95 'type' => 'boolean',
96 ],
97 static::$type . '_trim_lines' => [
98 'label' => __( 'Trim whitespace at the end of lines', 'pods' ),
99 'default' => 0,
100 'type' => 'boolean',
101 ],
102 static::$type . '_trim_p_brs' => [
103 'label' => __( 'Remove blank lines including empty "p" tags and "br" tags', 'pods' ),
104 'default' => 0,
105 'type' => 'boolean',
106 ],
107 static::$type . '_trim_extra_lines' => [
108 'label' => __( 'Remove extra blank lines (when there are 3+ blank lines, replace with a maximum of 2)', 'pods' ),
109 'default' => 0,
110 'type' => 'boolean',
111 ],
112 static::$type . '_sanitize_html' => [
113 'label' => __( 'Sanitize HTML', 'pods' ),
114 'default' => 1,
115 'help' => __( 'This sanitizes things like script tags and other content not normally allowed in WordPress content. Disable this only if you trust users who will have access to enter content into this field.', 'pods' ),
116 'type' => 'boolean',
117 'dependency' => true,
118 ],
119 static::$type . '_oembed' => [
120 'label' => __( 'Enable oEmbed', 'pods' ),
121 'default' => 0,
122 'type' => 'boolean',
123 'help' => [
124 __( 'Embed videos, images, tweets, and other content.', 'pods' ),
125 'https://wordpress.org/support/article/embeds/',
126 ],
127 ],
128 static::$type . '_wptexturize' => [
129 'label' => __( 'Enable wptexturize', 'pods' ),
130 'default' => 1,
131 'type' => 'boolean',
132 'help' => [
133 __( 'Transforms less-beautiful text characters into stylized equivalents.', 'pods' ),
134 'https://developer.wordpress.org/reference/functions/wptexturize/',
135 ],
136 ],
137 static::$type . '_convert_chars' => [
138 'label' => __( 'Enable convert_chars', 'pods' ),
139 'default' => 1,
140 'type' => 'boolean',
141 'help' => [
142 __( 'Converts text into valid XHTML and Unicode', 'pods' ),
143 'https://developer.wordpress.org/reference/functions/convert_chars/',
144 ],
145 ],
146 static::$type . '_wpautop' => [
147 'label' => __( 'Enable wpautop', 'pods' ),
148 'default' => 1,
149 'type' => 'boolean',
150 'help' => [
151 __( 'Changes double line-breaks in the text into HTML paragraphs', 'pods' ),
152 'https://developer.wordpress.org/reference/functions/wpautop/',
153 ],
154 ],
155 static::$type . '_allow_shortcode' => [
156 'label' => __( 'Allow Shortcodes', 'pods' ),
157 'default' => 0,
158 'type' => 'boolean',
159 'dependency' => true,
160 'help' => [
161 __( 'Embed [shortcodes] that help transform your static content into dynamic content.', 'pods' ),
162 'https://codex.wordpress.org/Shortcode_API',
163 ],
164 ],
165 ],
166 ],
167 static::$type . '_allowed_html_tags' => [
168 'label' => __( 'Allowed HTML Tags', 'pods' ),
169 'default' => '',
170 'type' => 'text',
171 'help' => __( 'Format: strong em a ul ol li b i', 'pods' ),
172 ],
173 ];
174
175 return $options;
176 }
177
178 /**
179 * {@inheritdoc}
180 */
181 public function schema( $options = null ) {
182
183 $schema = 'LONGTEXT';
184
185 return $schema;
186 }
187
188 /**
189 * {@inheritdoc}
190 */
191 public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
192 $value = $this->strip_html( $value, $options );
193
194 /**
195 * Allow filtering of the display value for the WYSIWYG field type before it's processed.
196 *
197 * NOTE: HTML has already been stripped at this point.
198 *
199 * @since 3.1.0
200 *
201 * @param mixed|null $value Current value.
202 * @param string $type Field type.
203 * @param string|null $name Field name.
204 * @param array|null $options Field options.
205 * @param array|null $pod Pod information.
206 * @param int|string|null $id Current item ID.
207 */
208 $value = apply_filters( 'pods_form_ui_field_wysiwyg_display_value_pre_process', $value, static::$type, $name, $options, $pod, $id );
209
210 $value = $this->strip_shortcodes( $value, $options );
211 $value = $this->trim_whitespace( $value, $options );
212
213 if ( 1 === (int) pods_v( static::$type . '_oembed', $options, 0 ) ) {
214 $post_temp = false;
215
216 // Workaround for WP_Embed since it needs a $post to work from
217 if ( 'post_type' === pods_v( 'type', $pod ) && 0 < $id && ( ! isset( $GLOBALS['post'] ) || empty( $GLOBALS['post'] ) ) ) {
218 $post_temp = true;
219
220 // @codingStandardsIgnoreLine
221 $GLOBALS['post'] = get_post( $id );
222 }
223
224 /**
225 * @var $embed WP_Embed
226 */
227 $embed = $GLOBALS['wp_embed'];
228 $value = $embed->run_shortcode( $value );
229 $value = $embed->autoembed( $value );
230
231 // Cleanup after ourselves
232 if ( $post_temp ) {
233 // @codingStandardsIgnoreLine
234 $GLOBALS['post'] = null;
235 }
236 }//end if
237
238 if ( 1 === (int) pods_v( static::$type . '_wptexturize', $options, 1 ) ) {
239 $value = wptexturize( $value );
240 }
241
242 if ( 1 === (int) pods_v( static::$type . '_convert_chars', $options, 1 ) ) {
243 $value = convert_chars( $value );
244 }
245
246 if ( 1 === (int) pods_v( static::$type . '_wpautop', $options, 1 ) ) {
247 $value = wpautop( $value );
248 }
249
250 if ( 1 === (int) pods_v( static::$type . '_allow_shortcode', $options, 0 ) ) {
251 if ( 1 === (int) pods_v( static::$type . '_wpautop', $options, 1 ) ) {
252 $value = shortcode_unautop( $value );
253 }
254
255 $value = do_shortcode( $value );
256 }
257
258 /**
259 * Allow filtering of the display value for the WYSIWYG field type.
260 *
261 * @since 3.1.0
262 *
263 * @param mixed|null $value Current value.
264 * @param string $type Field type.
265 * @param string|null $name Field name.
266 * @param array|null $options Field options.
267 * @param array|null $pod Pod information.
268 * @param int|string|null $id Current item ID.
269 */
270 return apply_filters( 'pods_form_ui_field_wysiwyg_display_value', $value, static::$type, $name, $options, $pod, $id );
271 }
272
273 /**
274 * {@inheritdoc}
275 */
276 public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
277
278 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
279 $form_field_type = PodsForm::$field_type;
280
281 // Force TinyMCE repeatable fields to not be repeatable because it lacks compatibility.
282 if ( 1 === (int) pods_v( 'repeatable', $options ) && 'tinymce' === pods_v( static::$type . '_editor', $options, 'tinymce', true ) ) {
283 $options['repeatable'] = 0;
284 }
285
286 $value = $this->maybe_sanitize_output( $value, $options );
287 $value = $this->normalize_value_for_input( $value, $options, "\n" );
288
289 // Normalize the line breaks for React.
290 if ( null !== $value ) {
291 $value = str_replace( "\r\n", "\n", $value );
292 $value = str_replace( "\r", "\n", $value );
293 }
294
295 if ( isset( $options['name'] ) && ! pods_permission( $options ) ) {
296 if ( pods_v_bool( 'read_only_restricted', $options ) ) {
297 $options['readonly'] = true;
298
299 $field_type = 'textarea';
300 } else {
301 return;
302 }
303 } elseif ( ! pods_has_permissions( $options ) && pods_v_bool( 'read_only', $options ) ) {
304 $options['readonly'] = true;
305
306 $field_type = 'textarea';
307 } elseif ( 'tinymce' === pods_v( static::$type . '_editor', $options ) ) {
308 // TinyMCE does not support repeatable.
309 if ( is_array( $value ) ) {
310 $value = implode( "\n", $value );
311 }
312
313 $field_type = 'tinymce';
314
315 // Enforce boolean.
316 $options[ static::$type . '_media_buttons' ] = filter_var( pods_v( static::$type . '_media_buttons', $options, true ), FILTER_VALIDATE_BOOLEAN );
317
318 // Set up default editor.
319 // @todo Support this properly in React, which will be a challenge.
320 $options[ static::$type . '_default_editor' ] = pods_v( static::$type . '_default_editor', $options, wp_default_editor(), true );
321
322 if ( in_array( $options[ static::$type . '_default_editor' ], [ 'html', 'tinymce' ], true ) ) {
323 $options[ static::$type . '_default_editor' ] = 'tinymce';
324 }
325
326 if (
327 (
328 function_exists( 'did_filter' )
329 && ! did_filter( 'tiny_mce_before_init' )
330 )
331 || ! did_action( 'enqueue_block_editor_assets' )
332 ) {
333 wp_tinymce_inline_scripts();
334 }
335
336 wp_enqueue_editor();
337
338 $settings = [];
339 $settings['textarea_name'] = $name;
340 $settings['media_buttons'] = false;
341
342 if ( ! ( defined( 'PODS_DISABLE_FILE_UPLOAD' ) && true === PODS_DISABLE_FILE_UPLOAD ) && ! ( defined( 'PODS_UPLOAD_REQUIRE_LOGIN' ) && is_bool( PODS_UPLOAD_REQUIRE_LOGIN ) && true === PODS_UPLOAD_REQUIRE_LOGIN && ! is_user_logged_in() ) && ! ( defined( 'PODS_UPLOAD_REQUIRE_LOGIN' ) && ! is_bool( PODS_UPLOAD_REQUIRE_LOGIN ) && ( ! is_user_logged_in() || ! current_user_can( PODS_UPLOAD_REQUIRE_LOGIN ) ) ) ) {
343 $settings['media_buttons'] = $options[ static::$type . '_media_buttons' ];
344 } else {
345 $options[ static::$type . '_media_buttons' ] = false;
346 }
347
348 $editor_height = (int) pods_v( static::$type . '_editor_height', $options, false );
349
350 if ( $editor_height ) {
351 $settings['editor_height'] = $editor_height;
352 }
353
354 if ( ! empty( $options[ static::$type . '_tinymce_settings' ] ) ) {
355 $settings = array_merge( $settings, $options[ static::$type . '_tinymce_settings' ] );
356 }
357
358 // WP will handle the scripting needed, but we won't output the textarea here.
359 ob_start();
360 wp_editor( (string) $value, '_pods_dfv_' . $name, $settings );
361 $unused_output = ob_get_clean();
362
363 // Workaround because the above already outputs the style we need.
364 $styles = wp_styles();
365
366 $found_editor_buttons = array_search( 'editor-buttons', $styles->done, true );
367
368 if ( false !== $found_editor_buttons ) {
369 unset( $styles->done[ $found_editor_buttons ] );
370 }
371
372 $found_dashicons = array_search( 'dashicons', $styles->done, true );
373
374 if ( false !== $found_dashicons ) {
375 unset( $styles->done[ $found_dashicons ] );
376 }
377
378 wp_print_styles( 'editor-buttons' );
379 wp_print_styles( 'dashicons' );
380 } elseif ( 'quill' === pods_v( static::$type . '_editor', $options ) ) {
381 $field_type = 'quill';
382 } elseif ( 'cleditor' === pods_v( static::$type . '_editor', $options ) ) {
383 $field_type = 'quill';
384 } else {
385 // Support custom WYSIWYG integration
386 $editor_type = pods_v( static::$type . '_editor', $options );
387 do_action( "pods_form_ui_field_wysiwyg_{$editor_type}", $name, $value, $options, $pod, $id );
388 do_action( 'pods_form_ui_field_wysiwyg', pods_v( static::$type . '_editor', $options ), $name, $value, $options, $pod, $id );
389
390 return;
391 }//end if
392
393 if ( ! empty( $options['disable_dfv'] ) ) {
394 return pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
395 }
396
397 $type = pods_v( 'type', $options, static::$type );
398
399 $args = compact( array_keys( get_defined_vars() ) );
400 $args = (object) $args;
401
402 $this->render_input_script( $args );
403 }
404
405 /**
406 * {@inheritdoc}
407 */
408 public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
409 $value = $this->strip_html( $value, $options );
410 $value = $this->strip_shortcodes( $value, $options );
411 $value = $this->trim_whitespace( $value, $options );
412
413 $length = (int) pods_v( static::$type . '_max_length', $options, 0 );
414
415 if ( 0 < $length && $length < pods_mb_strlen( $value ) ) {
416 $value = pods_mb_substr( $value, 0, $length );
417 }
418
419 return $value;
420 }
421
422 /**
423 * {@inheritdoc}
424 */
425 public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
426 $value = $this->strip_html( $value, $options );
427 $value = $this->strip_shortcodes( $value, $options );
428 $value = $this->trim_whitespace( $value, $options );
429
430 $value = wp_trim_words( $value );
431
432 return $value;
433 }
434
435 /**
436 * {@inheritdoc}
437 */
438 public function strip_html( $value, $options = null ) {
439
440 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
441
442 // Allow HTML tags.
443 $options[ static::$type . '_allow_html' ] = 1;
444
445 return parent::strip_html( $value, $options );
446 }
447 }
448