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