PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.0-beta2
Secure Custom Fields v6.4.0-beta2
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / fields / class-acf-field-wysiwyg.php
secure-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 1 year ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 1 year ago class-acf-field-date_time_picker.php 1 year ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-google-map.php 1 year ago class-acf-field-group.php 1 year ago class-acf-field-icon_picker.php 1 year ago class-acf-field-image.php 1 year ago class-acf-field-link.php 1 year ago class-acf-field-message.php 1 year ago class-acf-field-number.php 1 year ago class-acf-field-oembed.php 1 year ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 year ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 1 year ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 1 year ago class-acf-field-select.php 1 year ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 year ago class-acf-field-text.php 1 year ago class-acf-field-textarea.php 1 year ago class-acf-field-time_picker.php 1 year ago class-acf-field-true_false.php 1 year ago class-acf-field-url.php 1 year ago class-acf-field-user.php 1 year ago class-acf-field-wysiwyg.php 1 year ago class-acf-field.php 1 year ago index.php 1 year ago
class-acf-field-wysiwyg.php
418 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_wysiwyg' ) ) :
4
5 class acf_field_wysiwyg extends acf_field {
6
7
8 /**
9 * This function will setup the field type data
10 *
11 * @type function
12 * @date 5/03/2014
13 * @since 5.0.0
14 *
15 * @param n/a
16 * @return n/a
17 */
18 function initialize() {
19
20 // vars
21 $this->name = 'wysiwyg';
22 $this->label = __( 'WYSIWYG Editor', 'acf' );
23 $this->category = 'content';
24 $this->description = __( 'Displays the WordPress WYSIWYG editor as seen in Posts and Pages allowing for a rich text-editing experience that also allows for multimedia content.', 'acf' ) . ' ' . __( 'We do not recommend using this field in ACF Blocks.', 'acf' );
25 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-wysiwyg.png';
26 $this->doc_url = 'https://www.advancedcustomfields.com/resources/wysiwyg-editor/';
27 $this->defaults = array(
28 'tabs' => 'all',
29 'toolbar' => 'full',
30 'media_upload' => 1,
31 'default_value' => '',
32 'delay' => 0,
33 );
34 $this->supports = array(
35 'escaping_html' => true,
36 );
37
38 // add acf_the_content filters
39 $this->add_filters();
40
41 // actions
42 add_action( 'acf/enqueue_uploader', array( $this, 'acf_enqueue_uploader' ) );
43 }
44
45
46 /**
47 * This function will add filters to 'acf_the_content'
48 *
49 * @type function
50 * @date 20/09/2016
51 * @since 5.4.0
52 *
53 * @param n/a
54 * @return n/a
55 */
56 function add_filters() {
57
58 // WordPress 5.5 introduced new function for applying image tags.
59 $wp_filter_content_tags = function_exists( 'wp_filter_content_tags' ) ? 'wp_filter_content_tags' : 'wp_make_content_images_responsive';
60
61 // Mimic filters added to "the_content" in "wp-includes/default-filters.php".
62 add_filter( 'acf_the_content', 'capital_P_dangit', 11 );
63 // add_filter( 'acf_the_content', 'do_blocks', 9 ); Not yet supported.
64 add_filter( 'acf_the_content', 'wptexturize' );
65 add_filter( 'acf_the_content', 'convert_smilies', 20 );
66 add_filter( 'acf_the_content', 'wpautop' );
67 add_filter( 'acf_the_content', 'shortcode_unautop' );
68 // add_filter( 'acf_the_content', 'prepend_attachment' ); Causes double image on attachment page.
69 add_filter( 'acf_the_content', $wp_filter_content_tags );
70 add_filter( 'acf_the_content', 'do_shortcode', 11 );
71
72 // Mimic filters added to "the_content" in "wp-includes/class-wp-embed.php"
73 if ( isset( $GLOBALS['wp_embed'] ) ) {
74 add_filter( 'acf_the_content', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
75 add_filter( 'acf_the_content', array( $GLOBALS['wp_embed'], 'autoembed' ), 8 );
76 }
77 }
78
79
80 /**
81 * This function will return an array of toolbars for the WYSIWYG field
82 *
83 * @type function
84 * @date 18/04/2014
85 * @since 5.0.0
86 *
87 * @param n/a
88 * @return (array)
89 */
90 function get_toolbars() {
91
92 // vars
93 $editor_id = 'acf_content';
94 $toolbars = array();
95
96 // mce buttons (Full)
97 $mce_buttons = array( 'formatselect', 'bold', 'italic', 'bullist', 'numlist', 'blockquote', 'alignleft', 'aligncenter', 'alignright', 'link', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' );
98 $mce_buttons_2 = array( 'strikethrough', 'hr', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' );
99
100 // mce buttons (Basic)
101 $teeny_mce_buttons = array( 'bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'fullscreen' );
102
103 // Full
104 $toolbars['Full'] = array(
105 1 => apply_filters( 'mce_buttons', $mce_buttons, $editor_id ),
106 2 => apply_filters( 'mce_buttons_2', $mce_buttons_2, $editor_id ),
107 3 => apply_filters( 'mce_buttons_3', array(), $editor_id ),
108 4 => apply_filters( 'mce_buttons_4', array(), $editor_id ),
109 );
110
111 // Basic
112 $toolbars['Basic'] = array(
113 1 => apply_filters( 'teeny_mce_buttons', $teeny_mce_buttons, $editor_id ),
114 );
115
116 // Filter for 3rd party
117 $toolbars = apply_filters( 'acf/fields/wysiwyg/toolbars', $toolbars );
118
119 // return
120 return $toolbars;
121 }
122
123
124 /**
125 * Registers toolbars data for the WYSIWYG field.
126 *
127 * @type function
128 * @date 16/12/2015
129 * @since 5.3.2
130 *
131 * @param void
132 * @return void
133 */
134 function acf_enqueue_uploader() {
135
136 // vars
137 $data = array();
138 $toolbars = $this->get_toolbars();
139
140 // loop
141 if ( $toolbars ) {
142 foreach ( $toolbars as $label => $rows ) {
143
144 // vars
145 $key = $label;
146 $key = sanitize_title( $key );
147 $key = str_replace( '-', '_', $key );
148
149 // append
150 $data[ $key ] = array();
151
152 if ( $rows ) {
153 foreach ( $rows as $i => $row ) {
154 $data[ $key ][ $i ] = implode( ',', $row );
155 }
156 }
157 }
158 }
159
160 // localize
161 acf_localize_data(
162 array(
163 'toolbars' => $data,
164 )
165 );
166 }
167
168 /**
169 * Create the HTML interface for your field
170 *
171 * @param array $field An array holding all the field's data
172 *
173 * @type action
174 * @since 3.6
175 * @date 23/01/13
176 */
177 function render_field( $field ) {
178
179 // enqueue
180 acf_enqueue_uploader();
181
182 // vars
183 $id = uniqid( 'acf-editor-' );
184 $default_editor = 'html';
185 $show_tabs = true;
186
187 // get height
188 $height = acf_get_user_setting( 'wysiwyg_height', 300 );
189 $height = max( $height, 300 ); // minimum height is 300
190
191 // detect mode
192 if ( ! user_can_richedit() ) {
193 $show_tabs = false;
194 } elseif ( $field['tabs'] == 'visual' ) {
195
196 // case: visual tab only
197 $default_editor = 'tinymce';
198 $show_tabs = false;
199 } elseif ( $field['tabs'] == 'text' ) {
200
201 // case: text tab only
202 $show_tabs = false;
203 } elseif ( wp_default_editor() == 'tinymce' ) {
204
205 // case: both tabs
206 $default_editor = 'tinymce';
207 }
208
209 // must be logged in to upload
210 if ( ! current_user_can( 'upload_files' ) ) {
211 $field['media_upload'] = 0;
212 }
213
214 // mode
215 $switch_class = ( $default_editor === 'html' ) ? 'html-active' : 'tmce-active';
216
217 // filter
218 add_filter( 'acf_the_editor_content', 'format_for_editor', 10, 2 );
219
220 $field['value'] = is_string( $field['value'] ) ? $field['value'] : '';
221 $field['value'] = apply_filters( 'acf_the_editor_content', $field['value'], $default_editor );
222
223 // attr
224 $wrap = array(
225 'id' => 'wp-' . $id . '-wrap',
226 'class' => 'acf-editor-wrap wp-core-ui wp-editor-wrap ' . $switch_class,
227 'data-toolbar' => $field['toolbar'],
228 );
229
230 // delay
231 if ( $field['delay'] ) {
232 $wrap['class'] .= ' delay';
233 }
234
235 // vars
236 $textarea = acf_get_textarea_input(
237 array(
238 'id' => $id,
239 'class' => 'wp-editor-area',
240 'name' => $field['name'],
241 'style' => $height ? "height:{$height}px;" : '',
242 'value' => '%s',
243 )
244 );
245
246 ?>
247 <div <?php echo acf_esc_attrs( $wrap ); ?>>
248 <div id="wp-<?php echo esc_attr( $id ); ?>-editor-tools" class="wp-editor-tools hide-if-no-js">
249 <?php if ( $field['media_upload'] ) : ?>
250 <div id="wp-<?php echo esc_attr( $id ); ?>-media-buttons" class="wp-media-buttons">
251 <?php
252 if ( ! function_exists( 'media_buttons' ) ) {
253 require ABSPATH . 'wp-admin/includes/media.php';
254 }
255 do_action( 'media_buttons', $id );
256 ?>
257 </div>
258 <?php endif; ?>
259 <?php if ( user_can_richedit() && $show_tabs ) : ?>
260 <div class="wp-editor-tabs">
261 <button id="<?php echo esc_attr( $id ); ?>-tmce" class="wp-switch-editor switch-tmce" data-wp-editor-id="<?php echo esc_attr( $id ); ?>" type="button"><?php esc_html_e( 'Visual', 'acf' ); ?></button>
262 <button id="<?php echo esc_attr( $id ); ?>-html" class="wp-switch-editor switch-html" data-wp-editor-id="<?php echo esc_attr( $id ); ?>" type="button"><?php echo esc_html_x( 'Text', 'Name for the Text editor tab (formerly HTML)', 'acf' ); ?></button>
263 </div>
264 <?php endif; ?>
265 </div>
266 <div id="wp-<?php echo esc_attr( $id ); ?>-editor-container" class="wp-editor-container">
267 <?php if ( $field['delay'] ) : ?>
268 <div class="acf-editor-toolbar"><?php esc_html_e( 'Click to initialize TinyMCE', 'acf' ); ?></div>
269 <?php endif; ?>
270 <?php printf( $textarea, $field['value'] ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by format_for_editor(). ?>
271 </div>
272 </div>
273 <?php
274 }
275
276
277 /**
278 * Create extra options for your field. This is rendered when editing a field.
279 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
280 *
281 * @type action
282 * @since 3.6
283 * @date 23/01/13
284 *
285 * @param $field - an array holding all the field's data
286 */
287 function render_field_settings( $field ) {
288 acf_render_field_setting(
289 $field,
290 array(
291 'label' => __( 'Default Value', 'acf' ),
292 'instructions' => __( 'Appears when creating a new post', 'acf' ),
293 'type' => 'textarea',
294 'name' => 'default_value',
295 )
296 );
297 }
298
299 /**
300 * Renders the field settings used in the "Presentation" tab.
301 *
302 * @since 6.0
303 *
304 * @param array $field The field settings array.
305 * @return void
306 */
307 function render_field_presentation_settings( $field ) {
308 $toolbars = $this->get_toolbars();
309 $choices = array();
310
311 if ( ! empty( $toolbars ) ) {
312 foreach ( $toolbars as $k => $v ) {
313 $label = $k;
314 $name = sanitize_title( $label );
315 $name = str_replace( '-', '_', $name );
316
317 $choices[ $name ] = $label;
318 }
319 }
320
321 acf_render_field_setting(
322 $field,
323 array(
324 'label' => __( 'Tabs', 'acf' ),
325 'instructions' => '',
326 'type' => 'select',
327 'name' => 'tabs',
328 'choices' => array(
329 'all' => __( 'Visual & Text', 'acf' ),
330 'visual' => __( 'Visual Only', 'acf' ),
331 'text' => __( 'Text Only', 'acf' ),
332 ),
333 )
334 );
335
336 acf_render_field_setting(
337 $field,
338 array(
339 'label' => __( 'Toolbar', 'acf' ),
340 'instructions' => '',
341 'type' => 'select',
342 'name' => 'toolbar',
343 'choices' => $choices,
344 'conditions' => array(
345 'field' => 'tabs',
346 'operator' => '!=',
347 'value' => 'text',
348 ),
349 )
350 );
351
352 acf_render_field_setting(
353 $field,
354 array(
355 'label' => __( 'Show Media Upload Buttons', 'acf' ),
356 'instructions' => '',
357 'name' => 'media_upload',
358 'type' => 'true_false',
359 'ui' => 1,
360 )
361 );
362
363 acf_render_field_setting(
364 $field,
365 array(
366 'label' => __( 'Delay Initialization', 'acf' ),
367 'instructions' => __( 'TinyMCE will not be initialized until field is clicked', 'acf' ),
368 'name' => 'delay',
369 'type' => 'true_false',
370 'ui' => 1,
371 'conditions' => array(
372 'field' => 'tabs',
373 'operator' => '!=',
374 'value' => 'text',
375 ),
376 )
377 );
378 }
379 /**
380 * This filter is applied to the $value after it is loaded from the db, and before it is returned to the template
381 *
382 * @type filter
383 * @since 3.6
384 *
385 * @param mixed $value The value which was loaded from the database.
386 * @param mixed $post_id The $post_id from which the value was loaded.
387 * @param array $field The field array holding all the field options.
388 * @param boolean $escape_html Should the field return a HTML safe formatted value.
389 * @return mixed $value The modified value
390 */
391 public function format_value( $value, $post_id, $field, $escape_html ) {
392 // Bail early if no value or not a string.
393 if ( empty( $value ) || ! is_string( $value ) ) {
394 return $value;
395 }
396
397 if ( $escape_html ) {
398 add_filter( 'acf_the_content', 'acf_esc_html', 1 );
399 }
400
401 $value = apply_filters( 'acf_the_content', $value );
402
403 if ( $escape_html ) {
404 remove_filter( 'acf_the_content', 'acf_esc_html', 1 );
405 }
406
407 // Follow the_content function in /wp-includes/post-template.php
408 return str_replace( ']]>', ']]&gt;', $value );
409 }
410 }
411
412
413 // initialize
414 acf_register_field_type( 'acf_field_wysiwyg' );
415 endif; // class_exists check
416
417 ?>
418