WP_HTML_Processor
- Since
- 6.4.0
- Source
wp-includes/html-api/class-wp-html-processor.php:147
Description
The HTML Processor class properly parses and modifies HTML5 documents.
It supports a subset of the HTML5 specification, and when it encounters unsupported markup, it aborts early to avoid unintentionally breaking the document. The HTML Processor should never break an HTML document.
While the WP_HTML_Tag_Processor is a valuable tool for modifying attributes on individual HTML tags, the HTML Processor is more capable and useful for the following operations:
- Querying based on nested HTML structure.
Eventually the HTML Processor will also support:
- Wrapping a tag in surrounding HTML.
- Unwrapping a tag by removing its parent.
- Inserting and removing nodes.
- Reading and changing inner content.
- Navigating up or around HTML structure.
Usage
Use of this class requires three steps:
- Call a static creator method with your input HTML document.
- Find the location in the document you are looking for.
- Request changes to the document at that location.
Example:
$processor = WP_HTML_Processor::create_fragment( $html );
if ( $processor->next_tag( array( 'breadcrumbs' => array( 'DIV', 'FIGURE', 'IMG' ) ) ) ) {
$processor->add_class( 'responsive-image' );
} Breadcrumbs
Breadcrumbs represent the stack of open elements from the root of the document or fragment down to the currently-matched node, if one is currently selected. Call WP_HTML_Processor::get_breadcrumbs() to inspect the breadcrumbs for a matched tag.
Breadcrumbs can specify nested HTML structure and are equivalent to a CSS selector comprising tag names separated by the child combinator, such as "DIV > FIGURE > IMG".
Since all elements find themselves inside a full HTML document when parsed, the return value from get_breadcrumbs() will always contain any implicit outermost elements. For example, when parsing with create_fragment() in the BODY context (the default), any tag in the given HTML document will contain array( 'HTML', 'BODY', … ) in its breadcrumbs.
Despite containing the implied outermost elements in their breadcrumbs, tags may be found with the shortest-matching breadcrumb query. That is, array( 'IMG' ) matches all IMG elements and array( 'P', 'IMG' ) matches all IMG elements directly inside a P element. To ensure that no partial matches erroneously match it's possible to specify in a query the full breadcrumb match all the way down from the root HTML element.
Example:
$html = '<figure><img><figcaption>A <em>lovely</em> day outside</figcaption></figure>';
// ----- Matches here.
$processor->next_tag( array( 'breadcrumbs' => array( 'FIGURE', 'IMG' ) ) );
$html = '<figure><img><figcaption>A <em>lovely</em> day outside</figcaption></figure>';
// ---- Matches here.
$processor->next_tag( array( 'breadcrumbs' => array( 'FIGURE', 'FIGCAPTION', 'EM' ) ) );
$html = '<div><img></div><img>';
// ----- Matches here, because IMG must be a direct child of the implicit BODY.
$processor->next_tag( array( 'breadcrumbs' => array( 'BODY', 'IMG' ) ) ); HTML Support
This class implements a small part of the HTML5 specification.
It's designed to operate within its support and abort early whenever encountering circumstances it can't properly handle. This is the principle way in which this class remains as simple as possible without cutting corners and breaking compliance.
Supported elements
If any unsupported element appears in the HTML input the HTML Processor will abort early and stop all processing. This draconian measure ensures that the HTML Processor won't break any HTML it doesn't fully understand.
The HTML Processor supports all elements other than a specific set:
- Any element inside a TABLE.
- Any element inside foreign content, including SVG and MATH.
- Any element outside the IN BODY insertion mode, e.g. doctype declarations, meta, links.
Supported markup
Some kinds of non-normative HTML involve reconstruction of formatting elements and re-parenting of mis-nested elements. For example, a DIV tag found inside a TABLE may in fact belong before the table in the DOM. If the HTML Processor encounters such a case it will stop processing.
The following list illustrates some common examples of unexpected HTML inputs that the HTML Processor properly parses and represents:
- HTML with optional tags omitted, e.g.
<p>one<p>two. - HTML with unexpected tag closers, e.g.
<p>one </span> more</p>. - Non-void tags with self-closing flag, e.g.
<div/>the DIV is still open.</div>. - Heading elements which close open heading elements of another level, e.g.
<h1>Closed by </h2>. - Elements containing text that looks like other tags but isn't, e.g.
<title>The <img> is plaintext</title>. - SCRIPT and STYLE tags containing text that looks like HTML but isn't, e.g.
<script>document.write('<p>Hi</p>');</script>. - SCRIPT content which has been escaped, e.g.
<script><!-- document.write('<script>console.log("hi")</script>') --></script>.
Unsupported Features
This parser does not report parse errors.
Normally, when additional HTML or BODY tags are encountered in a document, if there are any additional attributes on them that aren't found on the previous elements, the existing HTML and BODY elements adopt those missing attribute values. This parser does not add those additional attributes.
In certain situations, elements are moved to a different part of the document in a process called "adoption" and "fostering." Because the nodes move to a location in the document that the parser had already processed, this parser does not support these situations and will bail.
The parser does not implement the "maybe clone an option into selectedcontent" algorithm.
SELECTEDCONTENT elements may not reflect the actual selected content.
Compatibility
- WordPress
- since 6.4.0
- 6.7.7
- 6.8.8
- 6.9.7
- 7.0.4
- 7.1.0
Present in every tracked release (6.7.7 to 7.1.0).
Properties · 9
$stateWP_HTML_Processor_Stateprivate- Holds the working state of the parser, including the stack of open elements and the stack of active formatting elements.
$bookmark_counterintprivate- Used to create unique bookmark names.
$last_errorstring|nullprivate- Stores an explanation for why something failed, if it did.
$unsupported_exceptionWP_HTML_Unsupported_Exception|nullprivate- Stores context for why the parser bailed on unsupported HTML, if it did.
$release_internal_bookmark_on_destructClosure|nullprivate- Releases a bookmark when PHP garbage-collects its wrapping WP_HTML_Token instance.
$element_queueWP_HTML_Stack_Event[]private- Stores stack events which arise during parsing of the HTML document, which will then supply the "match" events.
$breadcrumbsstring[]private- Stores the current breadcrumbs.
$current_elementWP_HTML_Stack_Event|nullprivate- Current stack event, if set, representing a matched token.
$context_nodeWP_HTML_Token|nullprivate- Context node if created as a fragment parser.
Methods · 79
- create_fragment()Creates an HTML processor in the fragment parsing mode.
- create_full_parser()Creates an HTML processor in the full parsing mode.
- __construct()Constructor.
- create_fragment_at_current_node()Creates a fragment processor at the current node.
- bail()Stops the parser and terminates its execution when encountering unsupported markup.
- get_last_error()Returns the last error, if any.
- get_unsupported_exception()Returns context for why the parser aborted due to unsupported HTML, if it did.
- next_tag()Finds the next tag matching the $query.
- next_token()Finds the next token in the HTML document.
- next_visitable_token()Ensures internal accounting is maintained for HTML semantic rules while the underlying Tag Processor class is seeking to a bookmark.
- is_tag_closer()Indicates if the current tag token is a tag closer.
- is_virtual()Indicates if the currently-matched token is virtual, created by a stack operation while processing HTML, rather than a token found in the HTML text itself.
- matches_breadcrumbs()Indicates if the currently-matched tag matches the given breadcrumbs.
- expects_closer()Indicates if the currently-matched node expects a closing token, or if it will self-close on the next step.
- step()Steps through the HTML document and stop at the next tag, if any.
- get_breadcrumbs()Computes the HTML breadcrumbs for the currently-matched node, if matched.
- get_current_depth()Returns the nesting depth of the current location in the document.
- normalize()Normalizes an HTML fragment by serializing it.
- serialize()Returns normalized HTML for a fragment by serializing it.
- serialize_token()Serializes the currently-matched token.
- escape_text_for_serialization()Escapes decoded text for HTML serialization.
- step_initial()Parses next element in the 'initial' insertion mode.
- step_before_html()Parses next element in the 'before html' insertion mode.
- step_before_head()Parses next element in the 'before head' insertion mode.
- step_in_head()Parses next element in the 'in head' insertion mode.
- step_in_head_noscript()Parses next element in the 'in head noscript' insertion mode.
- step_after_head()Parses next element in the 'after head' insertion mode.
- step_in_body()Parses next element in the 'in body' insertion mode.
- in_body_any_other_end_tag()Applies the "any other end tag" parsing instructions for the IN BODY insertion mode.
- step_in_table()Parses next element in the 'in table' insertion mode.
- step_in_table_text()Parses next element in the 'in table text' insertion mode.
- step_in_caption()Parses next element in the 'in caption' insertion mode.
- step_in_column_group()Parses next element in the 'in column group' insertion mode.
- step_in_table_body()Parses next element in the 'in table body' insertion mode.
- step_in_row()Parses next element in the 'in row' insertion mode.
- step_in_cell()Parses next element in the 'in cell' insertion mode.
- step_in_template()Parses next element in the 'in template' insertion mode.
- step_after_body()Parses next element in the 'after body' insertion mode.
- step_in_frameset()Parses next element in the 'in frameset' insertion mode.
- step_after_frameset()Parses next element in the 'after frameset' insertion mode.
- step_after_after_body()Parses next element in the 'after after body' insertion mode.
- step_after_after_frameset()Parses next element in the 'after after frameset' insertion mode.
- step_in_foreign_content()Parses next element in the 'in foreign content' insertion mode.
- bookmark_token()Creates a new bookmark for the currently-matched token and returns the generated name.
- get_namespace()Indicates the namespace of the current token, or "html" if there is none.
- get_tag()Returns the uppercase name of the matched tag.
- has_self_closing_flag()Indicates if the currently matched tag contains the self-closing flag.
- get_token_name()Returns the node name represented by the token.
- get_token_type()Indicates the kind of matched token, if any.
- get_attribute()Returns the value of a requested attribute from a matched tag opener if that attribute exists.
- set_attribute()Updates or creates a new attribute on the currently matched tag with the passed value.
- remove_attribute()Remove an attribute from the currently-matched tag.
- get_attribute_names_with_prefix()Gets lowercase names of all attributes matching a given prefix in the current tag.
- add_class()Adds a new class name to the currently matched tag.
- remove_class()Removes a class name from the currently matched tag.
- has_class()Returns if a matched tag contains the given ASCII case-insensitive class name.
- class_list()Generator for a foreach loop to step through each class name for the matched tag.
- get_modifiable_text()Returns the modifiable text for a matched token, or an empty string.
- get_comment_type()Indicates what kind of comment produced the comment node.
- release_bookmark()Removes a bookmark that is no longer needed.
- seek()Moves the internal cursor in the HTML Processor to a given bookmark's location.
- set_bookmark()Sets a bookmark in the HTML document.
- has_bookmark()Checks whether a bookmark with the given name exists.
- close_a_p_element()Closes a P element.
- generate_implied_end_tags()Closes elements that have implied end tags.
- generate_implied_end_tags_thoroughly()Closes elements that have implied end tags, thoroughly.
- get_adjusted_current_node()Returns the adjusted current node.
- reconstruct_active_formatting_elements()Reconstructs the active formatting elements.
- reset_insertion_mode_appropriately()Runs the reset the insertion mode appropriately algorithm.
- run_adoption_agency_algorithm()Runs the adoption agency algorithm.
- close_cell()Runs the "close the cell" algorithm.
- insert_html_element()Inserts an HTML element on the stack of open elements.
- insert_foreign_element()Inserts a foreign element on to the stack of open elements.
- insert_virtual_node()Inserts a virtual element on the stack of open elements.
- is_mathml_integration_point()Indicates if the current token is a MathML integration point.
- is_html_integration_point()Indicates if the current token is an HTML integration point.
- is_special()Returns whether an element of a given name is in the HTML special category.
- is_void()Returns whether a given element is an HTML Void Element
- get_encoding()Gets an encoding from a given string.
Source code
class WP_HTML_Processor extends WP_HTML_Tag_Processor { /** * The maximum number of bookmarks allowed to exist at any given time. * * HTML processing requires more bookmarks than basic tag processing, * so this class constant from the Tag Processor is overwritten. * * @since 6.4.0 * @since 7.0.0 Increased from 100 to 10,000 * * @var int */ const MAX_BOOKMARKS = 10_000; /** * Holds the working state of the parser, including the stack of * open elements and the stack of active formatting elements. * * Initialized in the constructor. * * @since 6.4.0 * * @var WP_HTML_Processor_State */ private $state; /** * Used to create unique bookmark names. * * This class sets a bookmark for every tag in the HTML document that it encounters. * The bookmark name is auto-generated and increments, starting with `1`. These are * internal bookmarks and are automatically released when the referring WP_HTML_Token * goes out of scope and is garbage-collected. * * @since 6.4.0 * * @see WP_HTML_Processor::$release_internal_bookmark_on_destruct * * @var int */ private $bookmark_counter = 0; /** * Stores an explanation for why something failed, if it did. * * @see self::get_last_error * * @since 6.4.0 * * @var string|null */ private $last_error = null; /** * Stores context for why the parser bailed on unsupported HTML, if it did. * * @see self::get_unsupported_exception * * @since 6.7.0 * * @var WP_HTML_Unsupported_Exception|null */ private $unsupported_exception = null; /** * Releases a bookmark when PHP garbage-collects its wrapping WP_HTML_Token instance. * * This function is created inside the class constructor so that it can be passed to * the stack of open elements and the stack of active formatting elements without * exposing it as a public method on the class. * * @since 6.4.0 * * @var Closure|null */ private $release_internal_bookmark_on_destruct = null; /** * Stores stack events which arise during parsing of the * HTML document, which will then supply the "match" events.Changelog
Introduced in 6.4.0. 5 changes between 6.7.7 and 7.1.0.
Signature, return type and hooks compared across 5 parsed releases.
escape_text_for_serialization() added.verified against sourcein_body_any_other_end_tag() added.verified against sourcestep_in_select() removed.verified against sourcestep_in_select_in_table() removed.verified against sourcecreate_fragment_at_current_node() added.verified against sourceAbout this page
- Parsed data
- Generated from the wordpress-develop 7.1.0 tag, from
src/wp-includes/html-api/class-wp-html-processor.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it. - Corrections
- Something wrong on this page? Report it and it gets fixed in the next regeneration.