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