Title: WP_HTML_Processor::serialize_token
Published: February 24, 2026
Last modified: August 20, 2026

---

# WP_HTML_Processor::serialize_token(): string

## In this article

 * [Description](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#description)
    - [See also](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#see-also)
 * [Return](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#source)
 * [Related](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#changelog)

[ Back to top](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#wp--skip-link--target)

Serializes the currently-matched token.

## 󠀁[Description](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#description)󠁿

This method produces a fully-normative HTML string for the currently-matched token,
if able. If not matched at any token or if the token doesn’t correspond to any HTML
it will return an empty string (for example, presumptuous end tags are ignored).

### 󠀁[See also](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#see-also)󠁿

 * [static::serialize()](https://developer.wordpress.org/reference/classes/static/serialize/)

## 󠀁[Return](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#return)󠁿

 string Serialization of token, or empty string if no serialization exists.

## 󠀁[Source](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#source)󠁿

    ```php
    public function serialize_token(): string {
    	$html       = '';
    	$token_type = $this->get_token_type();

    	switch ( $token_type ) {
    		case '#doctype':
    			$doctype = $this->get_doctype_info();
    			if ( null === $doctype ) {
    				break;
    			}

    			$html .= '<!DOCTYPE';

    			if ( $doctype->name ) {
    				$html .= " {$doctype->name}";
    			}

    			if ( null !== $doctype->public_identifier ) {
    				$quote = str_contains( $doctype->public_identifier, '"' ) ? "'" : '"';
    				$html .= " PUBLIC {$quote}{$doctype->public_identifier}{$quote}";
    			}
    			if ( null !== $doctype->system_identifier ) {
    				if ( null === $doctype->public_identifier ) {
    					$html .= ' SYSTEM';
    				}
    				$quote = str_contains( $doctype->system_identifier, '"' ) ? "'" : '"';
    				$html .= " {$quote}{$doctype->system_identifier}{$quote}";
    			}

    			$html .= '>';
    			break;

    		case '#text':
    			$html .= self::escape_text_for_serialization( $this->get_modifiable_text() );
    			break;

    		// Unlike the `<>` which is interpreted as plaintext, this is ignored entirely.
    		case '#presumptuous-tag':
    			break;

    		case '#funky-comment':
    		case '#comment':
    			$html .= "<!--{$this->get_full_comment_text()}-->";
    			break;

    		/**
    		 * Processing instructions are serialized as `"<?" target " " data "?>"`.
    		 *
    		 * @link https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments
    		 */
    		case '#processing-instruction':
    			$html .= "<?{$this->get_tag()} {$this->get_modifiable_text()}?>";
    			break;

    		case '#cdata-section':
    			$html .= "<![CDATA[{$this->get_modifiable_text()}]]>";
    			break;
    	}

    	if ( '#tag' !== $token_type ) {
    		return $html;
    	}

    	$tag_name       = $this->get_tag();
    	$in_html        = 'html' === $this->get_namespace();
    	$qualified_name = $in_html ? strtolower( $tag_name ) : $this->get_qualified_tag_name();

    	if ( $this->is_tag_closer() ) {
    		$html .= "</{$qualified_name}>";
    		return $html;
    	}

    	$attribute_names = $this->get_attribute_names_with_prefix( '' );
    	if ( ! isset( $attribute_names ) ) {
    		$html .= "<{$qualified_name}>";
    		return $html;
    	}

    	$html .= "<{$qualified_name}";

    	$previous_attribute_was_true = false;
    	$seen_attribute_names        = array();
    	foreach ( $attribute_names as $attribute_name ) {
    		$qualified_attribute_name = $this->get_qualified_attribute_name( $attribute_name );
    		$qualified_attribute_name = wp_scrub_utf8( $qualified_attribute_name );
    		/**
    		 * Spaces only appear via the foreign attribute adjustment table.
    		 * @see WP_HTML_Tag_Processor::get_qualified_attribute_name()
    		 */
    		$serialized_attribute_name = str_replace( ' ', ':', $qualified_attribute_name );
    		if ( isset( $seen_attribute_names[ $qualified_attribute_name ] ) ) {
    			continue;
    		} else {
    			$seen_attribute_names[ $qualified_attribute_name ] = true;
    		}

    		if (
    			$previous_attribute_was_true &&
    			isset( $serialized_attribute_name[0] ) &&
    			'=' === $serialized_attribute_name[0]
    		) {
    			$html .= '=""';
    		}

    		$html .= " {$serialized_attribute_name}";
    		$value = $this->get_attribute( $attribute_name );

    		if ( is_string( $value ) ) {
    			$html .= '="' . self::escape_text_for_serialization( $value ) . '"';
    		}

    		$previous_attribute_was_true = true === $value;
    	}

    	if ( ! $in_html && $this->has_self_closing_flag() ) {
    		$html .= ' /';
    	}

    	$html .= '>';

    	/*
    	 * The HTML parser strips a leading newline immediately after the start
    	 * tag of TEXTAREA, PRE, and LISTING elements in HTML content. When serializing,
    	 * prepend a leading newline to ensure the semantic HTML content is preserved.
    	 *
    	 * For example, `<pre>\n\nX</pre>` must not become `<pre>\nX</pre>` because its content
    	 * has changed. However, `<pre>X</pre>` and `<pre>\nX</pre>` are _equivalent_.
    	 *
    	 * > A start tag whose tag name is "textarea"
    	 * >   …
    	 * >   If the next token is a U+000A LINE FEED (LF) character token, then ignore
    	 * >   that token and move on to the next one. (Newlines at the start of textarea
    	 * >   elements are ignored as an authoring convenience.)
    	 *
    	 * > A start tag whose tag name is one of: "pre", "listing"
    	 * >   …
    	 * >   If the next token is a U+000A LINE FEED (LF) character token, then ignore
    	 * >   that token and move on to the next one. (Newlines at the start of pre blocks
    	 * >   are ignored as an authoring convenience.)
    	 *
    	 * @see https://html.spec.whatwg.org/multipage/parsing.html
    	 */
    	if ( $in_html && ( 'TEXTAREA' === $tag_name || 'PRE' === $tag_name || 'LISTING' === $tag_name ) ) {
    		$html .= "\n";
    	}

    	// Flush out self-contained elements.
    	if ( $in_html && in_array( $tag_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) {
    		$text = $this->get_modifiable_text();

    		switch ( $tag_name ) {
    			case 'IFRAME':
    			case 'NOEMBED':
    			case 'NOFRAMES':
    			case 'SCRIPT':
    			case 'STYLE':
    			case 'XMP':
    				break;

    			default:
    				$text = self::escape_text_for_serialization( $text );
    		}

    		$html .= "{$text}</{$qualified_name}>";
    	}

    	return $html;
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/html-api/class-wp-html-processor.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.1/src/wp-includes/html-api/class-wp-html-processor.php#L1357)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.1/src/wp-includes/html-api/class-wp-html-processor.php#L1357-L1524)

## 󠀁[Related](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#related)󠁿

| Uses | Description | 
| [WP_HTML_Processor::get_namespace()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_namespace/)`wp-includes/html-api/class-wp-html-processor.php` |

Indicates the namespace of the current token, or “html” if there is none.

  | 
| [wp_scrub_utf8()](https://developer.wordpress.org/reference/functions/wp_scrub_utf8/)`wp-includes/utf8.php` |

Replaces ill-formed UTF-8 byte sequences with the Unicode Replacement Character.

  | 
| [WP_HTML_Processor::get_modifiable_text()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_modifiable_text/)`wp-includes/html-api/class-wp-html-processor.php` |

Returns the modifiable text for a matched token, or an empty string.

  | 
| [WP_HTML_Processor::get_attribute()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_attribute/)`wp-includes/html-api/class-wp-html-processor.php` |

Returns the value of a requested attribute from a matched tag opener if that attribute exists.

  | 
| [WP_HTML_Processor::get_attribute_names_with_prefix()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_attribute_names_with_prefix/)`wp-includes/html-api/class-wp-html-processor.php` |

Gets lowercase names of all attributes matching a given prefix in the current tag.

  | 
| [WP_HTML_Processor::get_token_type()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_token_type/)`wp-includes/html-api/class-wp-html-processor.php` |

Indicates the kind of matched token, if any.

  | 
| [WP_HTML_Processor::has_self_closing_flag()](https://developer.wordpress.org/reference/classes/wp_html_processor/has_self_closing_flag/)`wp-includes/html-api/class-wp-html-processor.php` |

Indicates if the currently matched tag contains the self-closing flag.

  | 
| [WP_HTML_Processor::is_tag_closer()](https://developer.wordpress.org/reference/classes/wp_html_processor/is_tag_closer/)`wp-includes/html-api/class-wp-html-processor.php` |

Indicates if the current tag token is a tag closer.

  | 
| [WP_HTML_Processor::get_tag()](https://developer.wordpress.org/reference/classes/wp_html_processor/get_tag/)`wp-includes/html-api/class-wp-html-processor.php` |

Returns the uppercase name of the matched tag.

  |

[Show 4 more](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#)

| Used by | Description | 
| [WP_HTML_Processor::serialize()](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize/)`wp-includes/html-api/class-wp-html-processor.php` |

Returns normalized HTML for a fragment by serializing it.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/classes/wp_html_processor/serialize_token/?output_format=md#changelog)󠁿

| Version | Description | 
| [6.9.0](https://developer.wordpress.org/reference/since/6.9.0/) | Converted from protected to public method. | 
| [6.7.0](https://developer.wordpress.org/reference/since/6.7.0/) | Introduced. |

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwp_html_processor%2Fserialize_token%2F)
before being able to contribute a note or feedback.