PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.2.7
Pods – Custom Content Types and Fields v3.2.7
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 3 years ago boolean.php 3 years ago code.php 2 years ago color.php 3 years ago comment.php 4 years ago currency.php 3 years ago date.php 2 years ago datetime.php 2 years ago email.php 3 years ago file.php 1 year ago heading.php 2 years ago html.php 2 years ago link.php 3 years ago number.php 2 years ago oembed.php 2 years ago paragraph.php 2 years ago password.php 3 years ago phone.php 3 years ago pick.php 1 year ago slug.php 3 years ago taxonomy.php 4 years ago text.php 2 years ago time.php 2 years ago website.php 3 years ago wysiwyg.php 2 years ago
wysiwyg.php
437 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->maybe_sanitize_output( $value, $options );
276 $value = $this->normalize_value_for_input( $value, $options, "\n" );
277
278 // Normalize the line breaks for React.
279 if ( null !== $value ) {
280 $value = str_replace( "\r\n", "\n", $value );
281 $value = str_replace( "\r", "\n", $value );
282 }
283
284 if ( isset( $options['name'] ) && ! pods_permission( $options ) ) {
285 if ( pods_v( 'read_only', $options, false ) ) {
286 $options['readonly'] = true;
287
288 $field_type = 'textarea';
289 } else {
290 return;
291 }
292 } elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
293 $options['readonly'] = true;
294
295 $field_type = 'textarea';
296 } elseif ( 'tinymce' === pods_v( static::$type . '_editor', $options ) ) {
297 // TinyMCE does not support repeatable.
298 if ( is_array( $value ) ) {
299 $value = implode( "\n", $value );
300 }
301
302 $field_type = 'tinymce';
303
304 // Enforce boolean.
305 $options[ static::$type . '_media_buttons' ] = filter_var( pods_v( static::$type . '_media_buttons', $options, true ), FILTER_VALIDATE_BOOLEAN );
306
307 // Set up default editor.
308 // @todo Support this properly in React, which will be a challenge.
309 $options[ static::$type . '_default_editor' ] = pods_v( static::$type . '_default_editor', $options, wp_default_editor(), true );
310
311 if ( in_array( $options[ static::$type . '_default_editor' ], [ 'html', 'tinymce' ], true ) ) {
312 $options[ static::$type . '_default_editor' ] = 'tinymce';
313 }
314
315 if (
316 (
317 function_exists( 'did_filter' )
318 && ! did_filter( 'tiny_mce_before_init' )
319 )
320 || ! did_action( 'enqueue_block_editor_assets' )
321 ) {
322 wp_tinymce_inline_scripts();
323 }
324
325 wp_enqueue_editor();
326
327 $settings = [];
328 $settings['textarea_name'] = $name;
329 $settings['media_buttons'] = false;
330
331 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 ) ) ) ) {
332 $settings['media_buttons'] = $options[ static::$type . '_media_buttons' ];
333 } else {
334 $options[ static::$type . '_media_buttons' ] = false;
335 }
336
337 $editor_height = (int) pods_v( static::$type . '_editor_height', $options, false );
338
339 if ( $editor_height ) {
340 $settings['editor_height'] = $editor_height;
341 }
342
343 if ( ! empty( $options[ static::$type . '_tinymce_settings' ] ) ) {
344 $settings = array_merge( $settings, $options[ static::$type . '_tinymce_settings' ] );
345 }
346
347 // WP will handle the scripting needed, but we won't output the textarea here.
348 ob_start();
349 wp_editor( $value, '_pods_dfv_' . $name, $settings );
350 $unused_output = ob_get_clean();
351
352 // Workaround because the above already outputs the style we need.
353 $styles = wp_styles();
354
355 $found_editor_buttons = array_search( 'editor-buttons', $styles->done, true );
356
357 if ( false !== $found_editor_buttons ) {
358 unset( $styles->done[ $found_editor_buttons ] );
359 }
360
361 $found_dashicons = array_search( 'dashicons', $styles->done, true );
362
363 if ( false !== $found_dashicons ) {
364 unset( $styles->done[ $found_dashicons ] );
365 }
366
367 wp_print_styles( 'editor-buttons' );
368 wp_print_styles( 'dashicons' );
369 } elseif ( 'quill' === pods_v( static::$type . '_editor', $options ) ) {
370 $field_type = 'quill';
371 } elseif ( 'cleditor' === pods_v( static::$type . '_editor', $options ) ) {
372 $field_type = 'quill';
373 } else {
374 // Support custom WYSIWYG integration
375 $editor_type = pods_v( static::$type . '_editor', $options );
376 do_action( "pods_form_ui_field_wysiwyg_{$editor_type}", $name, $value, $options, $pod, $id );
377 do_action( 'pods_form_ui_field_wysiwyg', pods_v( static::$type . '_editor', $options ), $name, $value, $options, $pod, $id );
378
379 return;
380 }//end if
381
382 if ( ! empty( $options['disable_dfv'] ) ) {
383 return pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
384 }
385
386 $type = pods_v( 'type', $options, static::$type );
387
388 $args = compact( array_keys( get_defined_vars() ) );
389 $args = (object) $args;
390
391 $this->render_input_script( $args );
392 }
393
394 /**
395 * {@inheritdoc}
396 */
397 public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
398 $value = $this->strip_html( $value, $options );
399 $value = $this->strip_shortcodes( $value, $options );
400 $value = $this->trim_whitespace( $value, $options );
401
402 $length = (int) pods_v( static::$type . '_max_length', $options, 0 );
403
404 if ( 0 < $length && $length < pods_mb_strlen( $value ) ) {
405 $value = pods_mb_substr( $value, 0, $length );
406 }
407
408 return $value;
409 }
410
411 /**
412 * {@inheritdoc}
413 */
414 public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
415 $value = $this->strip_html( $value, $options );
416 $value = $this->strip_shortcodes( $value, $options );
417 $value = $this->trim_whitespace( $value, $options );
418
419 $value = wp_trim_words( $value );
420
421 return $value;
422 }
423
424 /**
425 * {@inheritdoc}
426 */
427 public function strip_html( $value, $options = null ) {
428
429 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
430
431 // Allow HTML tags.
432 $options[ static::$type . '_allow_html' ] = 1;
433
434 return parent::strip_html( $value, $options );
435 }
436 }
437