diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php
index e41e1120550b5..b18b0f2536cdb 100644
--- a/src/wp-includes/html-api/class-wp-html-tag-processor.php
+++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php
@@ -28,7 +28,9 @@
*
* Use of this class requires three steps:
*
- * 1. Create a new class instance with your input HTML document.
+ * 1. Create a new class instance with your input HTML document:
+ * `new WP_HTML_Tag_Processor( $html )`. This class has no static
+ * factory methods.
* 2. Find the tag(s) you are looking for.
* 3. Request changes to the attributes in those tag(s).
*
@@ -170,6 +172,35 @@
* of these methods are safe to call without knowing if a given attribute
* exists beforehand.
*
+ * ### Building markup from a template
+ *
+ * The Tag Processor can safely fill values into a known markup shape: write
+ * the shape as a literal template, then replace its attribute values and
+ * text through the API, which handles the necessary HTML encoding.
+ *
+ * Include attributes in the template, even with empty values, when their
+ * written order matters in the output. Updating an existing attribute
+ * replaces that attribute in place; adding a new attribute inserts it after
+ * the tag name, before existing attributes.
+ *
+ * Include placeholder text inside elements that need text content. An empty
+ * ordinary element has no `#text` token for
+ * {@see WP_HTML_Tag_Processor::set_modifiable_text} to replace.
+ *
+ * Example:
+ *
+ * $processor = new WP_HTML_Tag_Processor( '.' );
+ * $processor->next_tag();
+ * $processor->set_attribute( 'href', $url );
+ * $processor->set_attribute( 'title', $title );
+ * while ( $processor->next_token() ) {
+ * if ( '#text' === $processor->get_token_type() ) {
+ * $processor->set_modifiable_text( $link_text );
+ * break;
+ * }
+ * }
+ * $html = $processor->get_updated_html();
+ *
* ### Modifying CSS classes for a found tag
*
* The tag processor treats the `class` attribute as a special case.
@@ -3751,6 +3782,18 @@ public function get_modifiable_text(): string {
* language-specific escaping or workarounds. Similarly, it will not allow
* setting content into a comment which would prematurely terminate the comment.
*
+ * This method operates on the currently matched token, which must carry
+ * modifiable text: a `#text` node, a comment, or an element whose contents
+ * are raw text or plaintext. An ordinary container element, such as P, DIV,
+ * FIGCAPTION, or SPAN, carries no text of its own; its text lives in child
+ * `#text` tokens. Calling this method while matched on such a tag returns
+ * `false` and changes nothing. Always check the return value when the text
+ * update may be rejected.
+ *
+ * An empty ordinary element, such as ``, contains
+ * no `#text` token for this method to update. To fill empty elements when
+ * building markup from a template, include placeholder text and replace it.
+ *
* Example:
*
* // Add a preface to all STYLE contents.
@@ -4308,6 +4351,21 @@ private static function escape_javascript_script_contents( string $sourcecode ):
* - When `true` is passed as the value, then only the attribute name is added to the tag.
* - When `false` is passed, the attribute gets removed if it existed before.
*
+ * Updating an attribute the tag already has replaces its value in place, so
+ * the attribute keeps its position within the tag. A new attribute is
+ * inserted after the tag name, before existing attributes. When the exact
+ * attribute order of the output matters, start from markup in which the
+ * attributes already exist, even with empty values, and update them in
+ * place.
+ *
+ * Example:
+ *
+ * $processor = new WP_HTML_Tag_Processor( '
' );
+ * $processor->next_tag();
+ * $processor->set_attribute( 'src', '/dog.jpg' );
+ * $processor->set_attribute( 'alt', 'A dog' );
+ * //
+ *
* @since 6.2.0
* @since 6.2.1 Fix: Only create a single update for multiple calls with case-variant attribute names.
* @since 6.9.0 Escapes all character references instead of trying to avoid double-escaping.
@@ -4540,10 +4598,17 @@ public function remove_attribute( $name ): bool {
/**
* Adds a new class name to the currently matched tag.
*
+ * If the tag has no `class` attribute, one is created. If it already has
+ * classes, the new name is appended after them. Existing classes are not
+ * removed or reordered. Adding a class name the tag already has is a no-op:
+ * no duplicate is appended.
+ *
* @since 6.2.0
*
* @param string $class_name The class name to add.
- * @return bool Whether the class was set to be added.
+ * @return bool Whether the processor is matched on a tag and the class update
+ * was accepted. This can be true even when the class was already
+ * present and no duplicate will be added.
*/
public function add_class( $class_name ): bool {
if (
@@ -4622,7 +4687,20 @@ public function remove_class( $class_name ): bool {
}
/**
- * Returns the string representation of the HTML Tag Processor.
+ * Returns the input document with all queued updates applied.
+ *
+ * This is the way to read a document back after modifying it with
+ * {@see WP_HTML_Tag_Processor::set_attribute},
+ * {@see WP_HTML_Tag_Processor::remove_attribute},
+ * {@see WP_HTML_Tag_Processor::add_class},
+ * {@see WP_HTML_Tag_Processor::remove_class}, or
+ * {@see WP_HTML_Tag_Processor::set_modifiable_text}. Every byte not touched
+ * by an update is returned exactly as it appeared in the input; no
+ * normalization or reformatting occurs.
+ *
+ * Only attributes the API writes are re-emitted. Other attributes on the
+ * same tag keep their original bytes, including single-quoted or unquoted
+ * values. It is safe to call this method mid-scan and continue processing.
*
* @since 6.2.0
*