Widgets: Prevent visual Text widget from decoding encoded HTML.
Also apply `the_editor_content` filters on widget `text` with `format_for_editor()` as is done for the post editor. Amends [40631]. Props westonruter, azaozz. See #35243. Fixes #41596. git-svn-id: https://develop.svn.wordpress.org/trunk@41260 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
e0de3f6d1c
commit
66ee109e0a
@ -81,7 +81,7 @@ wp.textWidgets = ( function( $ ) {
|
||||
// Sync input fields to hidden sync fields which actually get sent to the server.
|
||||
_.each( control.fields, function( fieldInput, fieldName ) {
|
||||
fieldInput.on( 'input change', function updateSyncField() {
|
||||
var syncInput = control.syncContainer.find( 'input[type=hidden].' + fieldName );
|
||||
var syncInput = control.syncContainer.find( '.sync-input.' + fieldName );
|
||||
if ( syncInput.val() !== fieldInput.val() ) {
|
||||
syncInput.val( fieldInput.val() );
|
||||
syncInput.trigger( 'change' );
|
||||
@ -89,7 +89,7 @@ wp.textWidgets = ( function( $ ) {
|
||||
});
|
||||
|
||||
// Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event.
|
||||
fieldInput.val( control.syncContainer.find( 'input[type=hidden].' + fieldName ).val() );
|
||||
fieldInput.val( control.syncContainer.find( '.sync-input.' + fieldName ).val() );
|
||||
});
|
||||
},
|
||||
|
||||
@ -145,11 +145,11 @@ wp.textWidgets = ( function( $ ) {
|
||||
var control = this, syncInput;
|
||||
|
||||
if ( ! control.fields.title.is( document.activeElement ) ) {
|
||||
syncInput = control.syncContainer.find( 'input[type=hidden].title' );
|
||||
syncInput = control.syncContainer.find( '.sync-input.title' );
|
||||
control.fields.title.val( syncInput.val() );
|
||||
}
|
||||
|
||||
syncInput = control.syncContainer.find( 'input[type=hidden].text' );
|
||||
syncInput = control.syncContainer.find( '.sync-input.text' );
|
||||
if ( control.fields.text.is( ':visible' ) ) {
|
||||
if ( ! control.fields.text.is( document.activeElement ) ) {
|
||||
control.fields.text.val( syncInput.val() );
|
||||
|
@ -332,6 +332,7 @@ class WP_Widget_Text extends WP_Widget {
|
||||
* @since 4.8.0 Form only contains hidden inputs which are synced with JS template.
|
||||
* @since 4.8.1 Restored original form to be displayed when in legacy mode.
|
||||
* @see WP_Widget_Visual_Text::render_control_template_scripts()
|
||||
* @see _WP_Editors::editor()
|
||||
*
|
||||
* @param array $instance Current settings.
|
||||
* @return void
|
||||
@ -346,10 +347,31 @@ class WP_Widget_Text extends WP_Widget {
|
||||
);
|
||||
?>
|
||||
<?php if ( ! $this->is_legacy_instance( $instance ) ) : ?>
|
||||
<input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>">
|
||||
<input id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text" type="hidden" value="<?php echo esc_attr( $instance['text'] ); ?>">
|
||||
<input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter" type="hidden" value="on">
|
||||
<input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="on">
|
||||
<?php
|
||||
|
||||
if ( user_can_richedit() ) {
|
||||
add_filter( 'the_editor_content', 'format_for_editor', 10, 2 );
|
||||
$default_editor = 'tinymce';
|
||||
} else {
|
||||
$default_editor = 'html';
|
||||
}
|
||||
|
||||
/** This filter is documented in wp-includes/class-wp-editor.php */
|
||||
$text = apply_filters( 'the_editor_content', $instance['text'], $default_editor );
|
||||
|
||||
// Reset filter addition.
|
||||
if ( user_can_richedit() ) {
|
||||
remove_filter( 'the_editor_content', 'format_for_editor' );
|
||||
}
|
||||
|
||||
// Prevent premature closing of textarea in case format_for_editor() didn't apply or the_editor_content filter did a wrong thing.
|
||||
$escaped_text = preg_replace( '#</textarea#i', '</textarea', $text );
|
||||
|
||||
?>
|
||||
<input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title sync-input" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>">
|
||||
<textarea id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text sync-input" hidden><?php echo $escaped_text; ?></textarea>
|
||||
<input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter sync-input" type="hidden" value="on">
|
||||
<input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual sync-input" type="hidden" value="on">
|
||||
<?php else : ?>
|
||||
<input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="">
|
||||
<p>
|
||||
|
@ -447,7 +447,9 @@ class Test_WP_Widget_Text extends WP_UnitTestCase {
|
||||
* @covers WP_Widget_Text::form
|
||||
*/
|
||||
function test_form() {
|
||||
add_filter( 'user_can_richedit', '__return_true' );
|
||||
$widget = new WP_Widget_Text();
|
||||
$widget->_set( 2 );
|
||||
$instance = array(
|
||||
'title' => 'Title',
|
||||
'text' => 'Text',
|
||||
@ -459,7 +461,7 @@ class Test_WP_Widget_Text extends WP_UnitTestCase {
|
||||
$widget->form( $instance );
|
||||
$form = ob_get_clean();
|
||||
$this->assertContains( 'class="visual" type="hidden" value=""', $form );
|
||||
$this->assertNotContains( 'class="visual" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual sync-input" type="hidden" value="on"', $form );
|
||||
|
||||
$instance = array(
|
||||
'title' => 'Title',
|
||||
@ -470,8 +472,8 @@ class Test_WP_Widget_Text extends WP_UnitTestCase {
|
||||
ob_start();
|
||||
$widget->form( $instance );
|
||||
$form = ob_get_clean();
|
||||
$this->assertContains( 'class="visual" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
|
||||
$this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
|
||||
|
||||
$instance = array(
|
||||
'title' => 'Title',
|
||||
@ -482,12 +484,12 @@ class Test_WP_Widget_Text extends WP_UnitTestCase {
|
||||
ob_start();
|
||||
$widget->form( $instance );
|
||||
$form = ob_get_clean();
|
||||
$this->assertContains( 'class="visual" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
|
||||
$this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
|
||||
|
||||
$instance = array(
|
||||
'title' => 'Title',
|
||||
'text' => 'Text',
|
||||
'text' => 'This is some HTML Code: <code><strong>BOLD!</strong></code>',
|
||||
'filter' => true,
|
||||
'visual' => true,
|
||||
);
|
||||
@ -495,8 +497,24 @@ class Test_WP_Widget_Text extends WP_UnitTestCase {
|
||||
ob_start();
|
||||
$widget->form( $instance );
|
||||
$form = ob_get_clean();
|
||||
$this->assertContains( 'class="visual" type="hidden" value="on"', $form );
|
||||
$this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
|
||||
$this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
|
||||
$this->assertContains( '<code>&lt;strong&gt;BOLD!', $form );
|
||||
$this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
|
||||
|
||||
remove_filter( 'user_can_richedit', '__return_true' );
|
||||
add_filter( 'user_can_richedit', '__return_false' );
|
||||
$instance = array(
|
||||
'title' => 'Title',
|
||||
'text' => 'Evil:</textarea><script>alert("XSS")</script>',
|
||||
'filter' => true,
|
||||
'visual' => true,
|
||||
);
|
||||
$this->assertFalse( $widget->is_legacy_instance( $instance ) );
|
||||
ob_start();
|
||||
$widget->form( $instance );
|
||||
$form = ob_get_clean();
|
||||
$this->assertNotContains( 'Evil:</textarea>', $form );
|
||||
$this->assertContains( 'Evil:</textarea>', $form );
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user