Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Explore refactor of wp-editor code, adds set_modifiable_text()
  • Loading branch information
dmsnell committed Jan 25, 2024
commit ba8ff86e4f6ce49ea00d8d498b392cbcfcec72fb
85 changes: 59 additions & 26 deletions src/wp-includes/class-wp-editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,8 @@ public static function parse_settings( $editor_id, $settings ) {
*/
public static function editor( $content, $editor_id, $settings = array() ) {
$set = self::parse_settings( $editor_id, $settings );
$editor_class = ' class="' . trim( esc_attr( $set['editor_class'] ) . ' wp-editor-area' ) . '"';
$tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
$default_editor = 'html';
$buttons = '';
$autocomplete = '';
$editor_id_attr = esc_attr( $editor_id );

if ( $set['drag_drop_upload'] ) {
self::$drag_drop_upload = true;
Expand All @@ -180,19 +176,23 @@ public static function editor( $content, $editor_id, $settings = array() ) {
}

if ( self::$this_tinymce ) {
$autocomplete = ' autocomplete="off"';

if ( self::$this_quicktags ) {
$default_editor = $set['default_editor'] ? $set['default_editor'] : wp_default_editor();
// 'html' is used for the "Text" editor tab.
if ( 'html' !== $default_editor ) {
$default_editor = 'tinymce';
}

$buttons .= '<button type="button" id="' . $editor_id_attr . '-tmce" class="wp-switch-editor switch-tmce"' .
' data-wp-editor-id="' . $editor_id_attr . '">' . _x( 'Visual', 'Name for the Visual editor tab' ) . "</button>\n";
$buttons .= '<button type="button" id="' . $editor_id_attr . '-html" class="wp-switch-editor switch-html"' .
' data-wp-editor-id="' . $editor_id_attr . '">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</button>\n";
$buttons .= WP_HTML::render( <<<HTML
<button type="button" id="</%id>-tmce" class="wp-switch-editor switch-tmce" data-wp-editor-id="</%id>"></%visual_label></button>
<button type="button" id="</%id>-html" class="wp-switch-editor switch-html" data-wp-editor-id="</%id>"></%text_label></button>
HTML,
array(
'id' => $editor_id,
'text_label' => _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ),
'visual_label' => _x( 'Visual', 'Name for the Visual editor tab' ),
)
);
} else {
$default_editor = 'tinymce';
}
Expand All @@ -201,11 +201,13 @@ public static function editor( $content, $editor_id, $settings = array() ) {
$switch_class = 'html' === $default_editor ? 'html-active' : 'tmce-active';
$wrap_class = 'wp-core-ui wp-editor-wrap ' . $switch_class;

if ( $set['_content_editor_dfw'] ) {
$wrap_class .= ' has-dfw';
}

echo '<div id="wp-' . $editor_id_attr . '-wrap" class="' . $wrap_class . '">';
echo WP_HTML::render(
'<div id="wp-</%id>-wrap" class="wp-core-jui wp-editor-wrap </%has_dfw>">',
array(
'id' => $editor_id,
'has_dfw' => $set['_content_editor_dfw'] ? 'has-dfw' : '',
)
);

if ( self::$editor_buttons_css ) {
wp_print_styles( 'editor-buttons' );
Expand All @@ -217,7 +219,10 @@ public static function editor( $content, $editor_id, $settings = array() ) {
}

if ( ! empty( $buttons ) || $set['media_buttons'] ) {
echo '<div id="wp-' . $editor_id_attr . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
echo WP_HTML::render(
'<div id="wp-</%id>-editor-tools" class="wp-editor-tools hide-if-no-js">',
array( 'id' => $editor_id )
);

if ( $set['media_buttons'] ) {
self::$has_medialib = true;
Expand All @@ -226,7 +231,10 @@ public static function editor( $content, $editor_id, $settings = array() ) {
require ABSPATH . 'wp-admin/includes/media.php';
}

echo '<div id="wp-' . $editor_id_attr . '-media-buttons" class="wp-media-buttons">';
echo WP_HTML::render(
'<div id="wp-</%id>-media-button" class="wp-media-buttons">',
array( 'id' => $editor_id )
);

/**
* Fires after the default media button(s) are displayed.
Expand All @@ -249,10 +257,13 @@ public static function editor( $content, $editor_id, $settings = array() ) {
if ( 'content' === $editor_id && ! empty( $GLOBALS['current_screen'] ) && 'post' === $GLOBALS['current_screen']->base ) {
$toolbar_id = 'ed_toolbar';
} else {
$toolbar_id = 'qt_' . $editor_id_attr . '_toolbar';
$toolbar_id = 'qt_' . $editor_id . '_toolbar';
}

$quicktags_toolbar = '<div id="' . $toolbar_id . '" class="quicktags-toolbar hide-if-no-js"></div>';
$quicktags_toolbar = WP_HTML::render(
'<div id="</%id>" class="quicktags-toolbar hide-if-no-js"></div>',
array( 'id' => $toolbar_id )
);
}

/**
Expand All @@ -264,10 +275,28 @@ public static function editor( $content, $editor_id, $settings = array() ) {
*/
$the_editor = apply_filters(
'the_editor',
'<div id="wp-' . $editor_id_attr . '-editor-container" class="wp-editor-container">' .
WP_HTML::render(
'<div id="wp-</%id>-editor-container" class="wp-editor-container">',
array( 'id' => $editor_id )
) .
$quicktags_toolbar .
'<textarea' . $editor_class . $height . $tabindex . $autocomplete . ' cols="40" name="' . esc_attr( $set['textarea_name'] ) . '" ' .
'id="' . $editor_id_attr . '">%s</textarea></div>'
WP_HTML::render(
<<<'HTML'
<textarea class="</%editor_class>" ...height tabindex="</%tabindex>"
autocomplete="</%autocomplete>" cols="40" name="</%name>" id="</%id>">%s</textarea>
HTML,
array(
'autocomplete' => self::$this_tinymce ? 'off' : null,
'editor_class' => trim( "{$set['editor_class']} wp-editor-area" ),
'height' => ! empty( $set['editor_height'] )
? array( 'style' => "height: {$set['editor_height']}px;" )
: array( 'rows' => (string) $set['textarea_rows'] ),
'id' => $editor_id,
'name' => $set['textarea_name'],
'tabindex' => $set['tabindex'] ? (string) $set['tabindex'] : null,
)
) .
'</div>'
);

// Prepare the content for the Visual or Text editor, only when TinyMCE is used (back-compat).
Expand Down Expand Up @@ -300,12 +329,16 @@ public static function editor( $content, $editor_id, $settings = array() ) {
$content = apply_filters_deprecated( 'richedit_pre', array( $content ), '4.3.0', 'format_for_editor' );
}

if ( false !== stripos( $content, 'textarea' ) ) {
$content = preg_replace( '%</textarea%i', '&lt;/textarea', $content );
$processor = new WP_HTML_Tag_Processor( $the_editor );
while ( $processor->next_tag( 'TEXTAREA' ) ) {
if ( $editor_id === $processor->get_attribute( 'id' ) ) {
$processor->set_modifiable_text( $content );
break;
}
}
$the_editor = $processor->get_updated_html();

printf( $the_editor, $content );
echo "\n</div>\n\n";
echo "{$the_editor}\n</div>\n\n";

self::editor_settings( $editor_id, $set );
}
Expand Down
44 changes: 44 additions & 0 deletions src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2805,6 +2805,50 @@ public function get_modifiable_text() {
return $decoded;
}

/**
* Sets the modifiable text for the matched token, if possible.
*
* @param string $text Replace the modifiable text with this string.
* @return bool Whether the modifiable text was updated.
*/
public function set_modifiable_text( $text ) {
if ( null === $this->text_starts_at || ! is_string( $text ) ) {
return false;
}

switch ( $this->get_token_name() ) {
case '#text':
$this->lexical_updates[] = new WP_HTML_Text_Replacement(
$this->text_starts_at,
$this->text_length,
esc_html( $text )
);
break;

case 'TEXTAREA':
$this->lexical_updates[] = new WP_HTML_Text_Replacement(
$this->text_starts_at,
$this->text_length,
preg_replace( '~</textarea~i', '&lt;/textarea', $text )
);
break;

case 'TITLE':
$this->lexical_updates[] = new WP_HTML_Text_Replacement(
$this->text_starts_at,
$this->text_length,
preg_replace( '~</title~i', '&lt;/title', $text )
);
break;

default:
return false;
}

$this->get_updated_html();
return true;
}

/**
* Updates or creates a new attribute on the currently matched tag with the passed value.
*
Expand Down