Edit File by line

Deprecated: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in /home/sportsfever/public_html/filemanger/function.php on line 93
/home/sportsfe.../public_h.../wp-inclu.../html-api
File: class-wp-html-processor.php
<?php
[0] Fix | Delete
/**
[1] Fix | Delete
* HTML API: WP_HTML_Processor class
[2] Fix | Delete
*
[3] Fix | Delete
* @package WordPress
[4] Fix | Delete
* @subpackage HTML-API
[5] Fix | Delete
* @since 6.4.0
[6] Fix | Delete
*/
[7] Fix | Delete
[8] Fix | Delete
/**
[9] Fix | Delete
* Core class used to safely parse and modify an HTML document.
[10] Fix | Delete
*
[11] Fix | Delete
* The HTML Processor class properly parses and modifies HTML5 documents.
[12] Fix | Delete
*
[13] Fix | Delete
* It supports a subset of the HTML5 specification, and when it encounters
[14] Fix | Delete
* unsupported markup, it aborts early to avoid unintentionally breaking
[15] Fix | Delete
* the document. The HTML Processor should never break an HTML document.
[16] Fix | Delete
*
[17] Fix | Delete
* While the `WP_HTML_Tag_Processor` is a valuable tool for modifying
[18] Fix | Delete
* attributes on individual HTML tags, the HTML Processor is more capable
[19] Fix | Delete
* and useful for the following operations:
[20] Fix | Delete
*
[21] Fix | Delete
* - Querying based on nested HTML structure.
[22] Fix | Delete
*
[23] Fix | Delete
* Eventually the HTML Processor will also support:
[24] Fix | Delete
* - Wrapping a tag in surrounding HTML.
[25] Fix | Delete
* - Unwrapping a tag by removing its parent.
[26] Fix | Delete
* - Inserting and removing nodes.
[27] Fix | Delete
* - Reading and changing inner content.
[28] Fix | Delete
* - Navigating up or around HTML structure.
[29] Fix | Delete
*
[30] Fix | Delete
* ## Usage
[31] Fix | Delete
*
[32] Fix | Delete
* Use of this class requires three steps:
[33] Fix | Delete
*
[34] Fix | Delete
* 1. Call a static creator method with your input HTML document.
[35] Fix | Delete
* 2. Find the location in the document you are looking for.
[36] Fix | Delete
* 3. Request changes to the document at that location.
[37] Fix | Delete
*
[38] Fix | Delete
* Example:
[39] Fix | Delete
*
[40] Fix | Delete
* $processor = WP_HTML_Processor::create_fragment( $html );
[41] Fix | Delete
* if ( $processor->next_tag( array( 'breadcrumbs' => array( 'DIV', 'FIGURE', 'IMG' ) ) ) ) {
[42] Fix | Delete
* $processor->add_class( 'responsive-image' );
[43] Fix | Delete
* }
[44] Fix | Delete
*
[45] Fix | Delete
* #### Breadcrumbs
[46] Fix | Delete
*
[47] Fix | Delete
* Breadcrumbs represent the stack of open elements from the root
[48] Fix | Delete
* of the document or fragment down to the currently-matched node,
[49] Fix | Delete
* if one is currently selected. Call WP_HTML_Processor::get_breadcrumbs()
[50] Fix | Delete
* to inspect the breadcrumbs for a matched tag.
[51] Fix | Delete
*
[52] Fix | Delete
* Breadcrumbs can specify nested HTML structure and are equivalent
[53] Fix | Delete
* to a CSS selector comprising tag names separated by the child
[54] Fix | Delete
* combinator, such as "DIV > FIGURE > IMG".
[55] Fix | Delete
*
[56] Fix | Delete
* Since all elements find themselves inside a full HTML document
[57] Fix | Delete
* when parsed, the return value from `get_breadcrumbs()` will always
[58] Fix | Delete
* contain any implicit outermost elements. For example, when parsing
[59] Fix | Delete
* with `create_fragment()` in the `BODY` context (the default), any
[60] Fix | Delete
* tag in the given HTML document will contain `array( 'HTML', 'BODY', … )`
[61] Fix | Delete
* in its breadcrumbs.
[62] Fix | Delete
*
[63] Fix | Delete
* Despite containing the implied outermost elements in their breadcrumbs,
[64] Fix | Delete
* tags may be found with the shortest-matching breadcrumb query. That is,
[65] Fix | Delete
* `array( 'IMG' )` matches all IMG elements and `array( 'P', 'IMG' )`
[66] Fix | Delete
* matches all IMG elements directly inside a P element. To ensure that no
[67] Fix | Delete
* partial matches erroneously match it's possible to specify in a query
[68] Fix | Delete
* the full breadcrumb match all the way down from the root HTML element.
[69] Fix | Delete
*
[70] Fix | Delete
* Example:
[71] Fix | Delete
*
[72] Fix | Delete
* $html = '<figure><img><figcaption>A <em>lovely</em> day outside</figcaption></figure>';
[73] Fix | Delete
* // ----- Matches here.
[74] Fix | Delete
* $processor->next_tag( array( 'breadcrumbs' => array( 'FIGURE', 'IMG' ) ) );
[75] Fix | Delete
*
[76] Fix | Delete
* $html = '<figure><img><figcaption>A <em>lovely</em> day outside</figcaption></figure>';
[77] Fix | Delete
* // ---- Matches here.
[78] Fix | Delete
* $processor->next_tag( array( 'breadcrumbs' => array( 'FIGURE', 'FIGCAPTION', 'EM' ) ) );
[79] Fix | Delete
*
[80] Fix | Delete
* $html = '<div><img></div><img>';
[81] Fix | Delete
* // ----- Matches here, because IMG must be a direct child of the implicit BODY.
[82] Fix | Delete
* $processor->next_tag( array( 'breadcrumbs' => array( 'BODY', 'IMG' ) ) );
[83] Fix | Delete
*
[84] Fix | Delete
* ## HTML Support
[85] Fix | Delete
*
[86] Fix | Delete
* This class implements a small part of the HTML5 specification.
[87] Fix | Delete
* It's designed to operate within its support and abort early whenever
[88] Fix | Delete
* encountering circumstances it can't properly handle. This is
[89] Fix | Delete
* the principle way in which this class remains as simple as possible
[90] Fix | Delete
* without cutting corners and breaking compliance.
[91] Fix | Delete
*
[92] Fix | Delete
* ### Supported elements
[93] Fix | Delete
*
[94] Fix | Delete
* If any unsupported element appears in the HTML input the HTML Processor
[95] Fix | Delete
* will abort early and stop all processing. This draconian measure ensures
[96] Fix | Delete
* that the HTML Processor won't break any HTML it doesn't fully understand.
[97] Fix | Delete
*
[98] Fix | Delete
* The following list specifies the HTML tags that _are_ supported:
[99] Fix | Delete
*
[100] Fix | Delete
* - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY.
[101] Fix | Delete
* - Custom elements: All custom elements are supported. :)
[102] Fix | Delete
* - Form elements: BUTTON, DATALIST, FIELDSET, INPUT, LABEL, LEGEND, METER, PROGRESS, SEARCH.
[103] Fix | Delete
* - Formatting elements: B, BIG, CODE, EM, FONT, I, PRE, SMALL, STRIKE, STRONG, TT, U, WBR.
[104] Fix | Delete
* - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP.
[105] Fix | Delete
* - Links: A.
[106] Fix | Delete
* - Lists: DD, DL, DT, LI, OL, UL.
[107] Fix | Delete
* - Media elements: AUDIO, CANVAS, EMBED, FIGCAPTION, FIGURE, IMG, MAP, PICTURE, SOURCE, TRACK, VIDEO.
[108] Fix | Delete
* - Paragraph: BR, P.
[109] Fix | Delete
* - Phrasing elements: ABBR, AREA, BDI, BDO, CITE, DATA, DEL, DFN, INS, MARK, OUTPUT, Q, SAMP, SUB, SUP, TIME, VAR.
[110] Fix | Delete
* - Sectioning elements: ARTICLE, ASIDE, HR, NAV, SECTION.
[111] Fix | Delete
* - Templating elements: SLOT.
[112] Fix | Delete
* - Text decoration: RUBY.
[113] Fix | Delete
* - Deprecated elements: ACRONYM, BLINK, CENTER, DIR, ISINDEX, KEYGEN, LISTING, MULTICOL, NEXTID, PARAM, SPACER.
[114] Fix | Delete
*
[115] Fix | Delete
* ### Supported markup
[116] Fix | Delete
*
[117] Fix | Delete
* Some kinds of non-normative HTML involve reconstruction of formatting elements and
[118] Fix | Delete
* re-parenting of mis-nested elements. For example, a DIV tag found inside a TABLE
[119] Fix | Delete
* may in fact belong _before_ the table in the DOM. If the HTML Processor encounters
[120] Fix | Delete
* such a case it will stop processing.
[121] Fix | Delete
*
[122] Fix | Delete
* The following list specifies HTML markup that _is_ supported:
[123] Fix | Delete
*
[124] Fix | Delete
* - Markup involving only those tags listed above.
[125] Fix | Delete
* - Fully-balanced and non-overlapping tags.
[126] Fix | Delete
* - HTML with unexpected tag closers.
[127] Fix | Delete
* - Some unbalanced or overlapping tags.
[128] Fix | Delete
* - P tags after unclosed P tags.
[129] Fix | Delete
* - BUTTON tags after unclosed BUTTON tags.
[130] Fix | Delete
* - A tags after unclosed A tags that don't involve any active formatting elements.
[131] Fix | Delete
*
[132] Fix | Delete
* @since 6.4.0
[133] Fix | Delete
*
[134] Fix | Delete
* @see WP_HTML_Tag_Processor
[135] Fix | Delete
* @see https://html.spec.whatwg.org/
[136] Fix | Delete
*/
[137] Fix | Delete
class WP_HTML_Processor extends WP_HTML_Tag_Processor {
[138] Fix | Delete
/**
[139] Fix | Delete
* The maximum number of bookmarks allowed to exist at any given time.
[140] Fix | Delete
*
[141] Fix | Delete
* HTML processing requires more bookmarks than basic tag processing,
[142] Fix | Delete
* so this class constant from the Tag Processor is overwritten.
[143] Fix | Delete
*
[144] Fix | Delete
* @since 6.4.0
[145] Fix | Delete
*
[146] Fix | Delete
* @var int
[147] Fix | Delete
*/
[148] Fix | Delete
const MAX_BOOKMARKS = 100;
[149] Fix | Delete
[150] Fix | Delete
/**
[151] Fix | Delete
* Holds the working state of the parser, including the stack of
[152] Fix | Delete
* open elements and the stack of active formatting elements.
[153] Fix | Delete
*
[154] Fix | Delete
* Initialized in the constructor.
[155] Fix | Delete
*
[156] Fix | Delete
* @since 6.4.0
[157] Fix | Delete
*
[158] Fix | Delete
* @var WP_HTML_Processor_State
[159] Fix | Delete
*/
[160] Fix | Delete
private $state = null;
[161] Fix | Delete
[162] Fix | Delete
/**
[163] Fix | Delete
* Used to create unique bookmark names.
[164] Fix | Delete
*
[165] Fix | Delete
* This class sets a bookmark for every tag in the HTML document that it encounters.
[166] Fix | Delete
* The bookmark name is auto-generated and increments, starting with `1`. These are
[167] Fix | Delete
* internal bookmarks and are automatically released when the referring WP_HTML_Token
[168] Fix | Delete
* goes out of scope and is garbage-collected.
[169] Fix | Delete
*
[170] Fix | Delete
* @since 6.4.0
[171] Fix | Delete
*
[172] Fix | Delete
* @see WP_HTML_Processor::$release_internal_bookmark_on_destruct
[173] Fix | Delete
*
[174] Fix | Delete
* @var int
[175] Fix | Delete
*/
[176] Fix | Delete
private $bookmark_counter = 0;
[177] Fix | Delete
[178] Fix | Delete
/**
[179] Fix | Delete
* Stores an explanation for why something failed, if it did.
[180] Fix | Delete
*
[181] Fix | Delete
* @see self::get_last_error
[182] Fix | Delete
*
[183] Fix | Delete
* @since 6.4.0
[184] Fix | Delete
*
[185] Fix | Delete
* @var string|null
[186] Fix | Delete
*/
[187] Fix | Delete
private $last_error = null;
[188] Fix | Delete
[189] Fix | Delete
/**
[190] Fix | Delete
* Releases a bookmark when PHP garbage-collects its wrapping WP_HTML_Token instance.
[191] Fix | Delete
*
[192] Fix | Delete
* This function is created inside the class constructor so that it can be passed to
[193] Fix | Delete
* the stack of open elements and the stack of active formatting elements without
[194] Fix | Delete
* exposing it as a public method on the class.
[195] Fix | Delete
*
[196] Fix | Delete
* @since 6.4.0
[197] Fix | Delete
*
[198] Fix | Delete
* @var closure
[199] Fix | Delete
*/
[200] Fix | Delete
private $release_internal_bookmark_on_destruct = null;
[201] Fix | Delete
[202] Fix | Delete
/**
[203] Fix | Delete
* Stores stack events which arise during parsing of the
[204] Fix | Delete
* HTML document, which will then supply the "match" events.
[205] Fix | Delete
*
[206] Fix | Delete
* @since 6.6.0
[207] Fix | Delete
*
[208] Fix | Delete
* @var WP_HTML_Stack_Event[]
[209] Fix | Delete
*/
[210] Fix | Delete
private $element_queue = array();
[211] Fix | Delete
[212] Fix | Delete
/**
[213] Fix | Delete
* Current stack event, if set, representing a matched token.
[214] Fix | Delete
*
[215] Fix | Delete
* Because the parser may internally point to a place further along in a document
[216] Fix | Delete
* than the nodes which have already been processed (some "virtual" nodes may have
[217] Fix | Delete
* appeared while scanning the HTML document), this will point at the "current" node
[218] Fix | Delete
* being processed. It comes from the front of the element queue.
[219] Fix | Delete
*
[220] Fix | Delete
* @since 6.6.0
[221] Fix | Delete
*
[222] Fix | Delete
* @var ?WP_HTML_Stack_Event
[223] Fix | Delete
*/
[224] Fix | Delete
private $current_element = null;
[225] Fix | Delete
[226] Fix | Delete
/**
[227] Fix | Delete
* Context node if created as a fragment parser.
[228] Fix | Delete
*
[229] Fix | Delete
* @var ?WP_HTML_Token
[230] Fix | Delete
*/
[231] Fix | Delete
private $context_node = null;
[232] Fix | Delete
[233] Fix | Delete
/**
[234] Fix | Delete
* Whether the parser has yet processed the context node,
[235] Fix | Delete
* if created as a fragment parser.
[236] Fix | Delete
*
[237] Fix | Delete
* The context node will be initially pushed onto the stack of open elements,
[238] Fix | Delete
* but when created as a fragment parser, this context element (and the implicit
[239] Fix | Delete
* HTML document node above it) should not be exposed as a matched token or node.
[240] Fix | Delete
*
[241] Fix | Delete
* This boolean indicates whether the processor should skip over the current
[242] Fix | Delete
* node in its initial search for the first node created from the input HTML.
[243] Fix | Delete
*
[244] Fix | Delete
* @var bool
[245] Fix | Delete
*/
[246] Fix | Delete
private $has_seen_context_node = false;
[247] Fix | Delete
[248] Fix | Delete
/*
[249] Fix | Delete
* Public Interface Functions
[250] Fix | Delete
*/
[251] Fix | Delete
[252] Fix | Delete
/**
[253] Fix | Delete
* Creates an HTML processor in the fragment parsing mode.
[254] Fix | Delete
*
[255] Fix | Delete
* Use this for cases where you are processing chunks of HTML that
[256] Fix | Delete
* will be found within a bigger HTML document, such as rendered
[257] Fix | Delete
* block output that exists within a post, `the_content` inside a
[258] Fix | Delete
* rendered site layout.
[259] Fix | Delete
*
[260] Fix | Delete
* Fragment parsing occurs within a context, which is an HTML element
[261] Fix | Delete
* that the document will eventually be placed in. It becomes important
[262] Fix | Delete
* when special elements have different rules than others, such as inside
[263] Fix | Delete
* a TEXTAREA or a TITLE tag where things that look like tags are text,
[264] Fix | Delete
* or inside a SCRIPT tag where things that look like HTML syntax are JS.
[265] Fix | Delete
*
[266] Fix | Delete
* The context value should be a representation of the tag into which the
[267] Fix | Delete
* HTML is found. For most cases this will be the body element. The HTML
[268] Fix | Delete
* form is provided because a context element may have attributes that
[269] Fix | Delete
* impact the parse, such as with a SCRIPT tag and its `type` attribute.
[270] Fix | Delete
*
[271] Fix | Delete
* ## Current HTML Support
[272] Fix | Delete
*
[273] Fix | Delete
* - The only supported context is `<body>`, which is the default value.
[274] Fix | Delete
* - The only supported document encoding is `UTF-8`, which is the default value.
[275] Fix | Delete
*
[276] Fix | Delete
* @since 6.4.0
[277] Fix | Delete
* @since 6.6.0 Returns `static` instead of `self` so it can create subclass instances.
[278] Fix | Delete
*
[279] Fix | Delete
* @param string $html Input HTML fragment to process.
[280] Fix | Delete
* @param string $context Context element for the fragment, must be default of `<body>`.
[281] Fix | Delete
* @param string $encoding Text encoding of the document; must be default of 'UTF-8'.
[282] Fix | Delete
* @return static|null The created processor if successful, otherwise null.
[283] Fix | Delete
*/
[284] Fix | Delete
public static function create_fragment( $html, $context = '<body>', $encoding = 'UTF-8' ) {
[285] Fix | Delete
if ( '<body>' !== $context || 'UTF-8' !== $encoding ) {
[286] Fix | Delete
return null;
[287] Fix | Delete
}
[288] Fix | Delete
[289] Fix | Delete
$processor = new static( $html, self::CONSTRUCTOR_UNLOCK_CODE );
[290] Fix | Delete
$processor->state->context_node = array( 'BODY', array() );
[291] Fix | Delete
$processor->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY;
[292] Fix | Delete
[293] Fix | Delete
// @todo Create "fake" bookmarks for non-existent but implied nodes.
[294] Fix | Delete
$processor->bookmarks['root-node'] = new WP_HTML_Span( 0, 0 );
[295] Fix | Delete
$processor->bookmarks['context-node'] = new WP_HTML_Span( 0, 0 );
[296] Fix | Delete
[297] Fix | Delete
$processor->state->stack_of_open_elements->push(
[298] Fix | Delete
new WP_HTML_Token(
[299] Fix | Delete
'root-node',
[300] Fix | Delete
'HTML',
[301] Fix | Delete
false
[302] Fix | Delete
)
[303] Fix | Delete
);
[304] Fix | Delete
[305] Fix | Delete
$context_node = new WP_HTML_Token(
[306] Fix | Delete
'context-node',
[307] Fix | Delete
$processor->state->context_node[0],
[308] Fix | Delete
false
[309] Fix | Delete
);
[310] Fix | Delete
[311] Fix | Delete
$processor->state->stack_of_open_elements->push( $context_node );
[312] Fix | Delete
$processor->context_node = $context_node;
[313] Fix | Delete
[314] Fix | Delete
return $processor;
[315] Fix | Delete
}
[316] Fix | Delete
[317] Fix | Delete
/**
[318] Fix | Delete
* Constructor.
[319] Fix | Delete
*
[320] Fix | Delete
* Do not use this method. Use the static creator methods instead.
[321] Fix | Delete
*
[322] Fix | Delete
* @access private
[323] Fix | Delete
*
[324] Fix | Delete
* @since 6.4.0
[325] Fix | Delete
*
[326] Fix | Delete
* @see WP_HTML_Processor::create_fragment()
[327] Fix | Delete
*
[328] Fix | Delete
* @param string $html HTML to process.
[329] Fix | Delete
* @param string|null $use_the_static_create_methods_instead This constructor should not be called manually.
[330] Fix | Delete
*/
[331] Fix | Delete
public function __construct( $html, $use_the_static_create_methods_instead = null ) {
[332] Fix | Delete
parent::__construct( $html );
[333] Fix | Delete
[334] Fix | Delete
if ( self::CONSTRUCTOR_UNLOCK_CODE !== $use_the_static_create_methods_instead ) {
[335] Fix | Delete
_doing_it_wrong(
[336] Fix | Delete
__METHOD__,
[337] Fix | Delete
sprintf(
[338] Fix | Delete
/* translators: %s: WP_HTML_Processor::create_fragment(). */
[339] Fix | Delete
__( 'Call %s to create an HTML Processor instead of calling the constructor directly.' ),
[340] Fix | Delete
'<code>WP_HTML_Processor::create_fragment()</code>'
[341] Fix | Delete
),
[342] Fix | Delete
'6.4.0'
[343] Fix | Delete
);
[344] Fix | Delete
}
[345] Fix | Delete
[346] Fix | Delete
$this->state = new WP_HTML_Processor_State();
[347] Fix | Delete
[348] Fix | Delete
$this->state->stack_of_open_elements->set_push_handler(
[349] Fix | Delete
function ( WP_HTML_Token $token ) {
[350] Fix | Delete
$is_virtual = ! isset( $this->state->current_token ) || $this->is_tag_closer();
[351] Fix | Delete
$same_node = isset( $this->state->current_token ) && $token->node_name === $this->state->current_token->node_name;
[352] Fix | Delete
$provenance = ( ! $same_node || $is_virtual ) ? 'virtual' : 'real';
[353] Fix | Delete
$this->element_queue[] = new WP_HTML_Stack_Event( $token, WP_HTML_Stack_Event::PUSH, $provenance );
[354] Fix | Delete
}
[355] Fix | Delete
);
[356] Fix | Delete
[357] Fix | Delete
$this->state->stack_of_open_elements->set_pop_handler(
[358] Fix | Delete
function ( WP_HTML_Token $token ) {
[359] Fix | Delete
$is_virtual = ! isset( $this->state->current_token ) || ! $this->is_tag_closer();
[360] Fix | Delete
$same_node = isset( $this->state->current_token ) && $token->node_name === $this->state->current_token->node_name;
[361] Fix | Delete
$provenance = ( ! $same_node || $is_virtual ) ? 'virtual' : 'real';
[362] Fix | Delete
$this->element_queue[] = new WP_HTML_Stack_Event( $token, WP_HTML_Stack_Event::POP, $provenance );
[363] Fix | Delete
}
[364] Fix | Delete
);
[365] Fix | Delete
[366] Fix | Delete
/*
[367] Fix | Delete
* Create this wrapper so that it's possible to pass
[368] Fix | Delete
* a private method into WP_HTML_Token classes without
[369] Fix | Delete
* exposing it to any public API.
[370] Fix | Delete
*/
[371] Fix | Delete
$this->release_internal_bookmark_on_destruct = function ( $name ) {
[372] Fix | Delete
parent::release_bookmark( $name );
[373] Fix | Delete
};
[374] Fix | Delete
}
[375] Fix | Delete
[376] Fix | Delete
/**
[377] Fix | Delete
* Returns the last error, if any.
[378] Fix | Delete
*
[379] Fix | Delete
* Various situations lead to parsing failure but this class will
[380] Fix | Delete
* return `false` in all those cases. To determine why something
[381] Fix | Delete
* failed it's possible to request the last error. This can be
[382] Fix | Delete
* helpful to know to distinguish whether a given tag couldn't
[383] Fix | Delete
* be found or if content in the document caused the processor
[384] Fix | Delete
* to give up and abort processing.
[385] Fix | Delete
*
[386] Fix | Delete
* Example
[387] Fix | Delete
*
[388] Fix | Delete
* $processor = WP_HTML_Processor::create_fragment( '<template><strong><button><em><p><em>' );
[389] Fix | Delete
* false === $processor->next_tag();
[390] Fix | Delete
* WP_HTML_Processor::ERROR_UNSUPPORTED === $processor->get_last_error();
[391] Fix | Delete
*
[392] Fix | Delete
* @since 6.4.0
[393] Fix | Delete
*
[394] Fix | Delete
* @see self::ERROR_UNSUPPORTED
[395] Fix | Delete
* @see self::ERROR_EXCEEDED_MAX_BOOKMARKS
[396] Fix | Delete
*
[397] Fix | Delete
* @return string|null The last error, if one exists, otherwise null.
[398] Fix | Delete
*/
[399] Fix | Delete
public function get_last_error() {
[400] Fix | Delete
return $this->last_error;
[401] Fix | Delete
}
[402] Fix | Delete
[403] Fix | Delete
/**
[404] Fix | Delete
* Finds the next tag matching the $query.
[405] Fix | Delete
*
[406] Fix | Delete
* @todo Support matching the class name and tag name.
[407] Fix | Delete
*
[408] Fix | Delete
* @since 6.4.0
[409] Fix | Delete
* @since 6.6.0 Visits all tokens, including virtual ones.
[410] Fix | Delete
*
[411] Fix | Delete
* @throws Exception When unable to allocate a bookmark for the next token in the input HTML document.
[412] Fix | Delete
*
[413] Fix | Delete
* @param array|string|null $query {
[414] Fix | Delete
* Optional. Which tag name to find, having which class, etc. Default is to find any tag.
[415] Fix | Delete
*
[416] Fix | Delete
* @type string|null $tag_name Which tag to find, or `null` for "any tag."
[417] Fix | Delete
* @type string $tag_closers 'visit' to pause at tag closers, 'skip' or unset to only visit openers.
[418] Fix | Delete
* @type int|null $match_offset Find the Nth tag matching all search criteria.
[419] Fix | Delete
* 1 for "first" tag, 3 for "third," etc.
[420] Fix | Delete
* Defaults to first tag.
[421] Fix | Delete
* @type string|null $class_name Tag must contain this whole class name to match.
[422] Fix | Delete
* @type string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`.
[423] Fix | Delete
* May also contain the wildcard `*` which matches a single element, e.g. `array( 'SECTION', '*' )`.
[424] Fix | Delete
* }
[425] Fix | Delete
* @return bool Whether a tag was matched.
[426] Fix | Delete
*/
[427] Fix | Delete
public function next_tag( $query = null ) {
[428] Fix | Delete
$visit_closers = isset( $query['tag_closers'] ) && 'visit' === $query['tag_closers'];
[429] Fix | Delete
[430] Fix | Delete
if ( null === $query ) {
[431] Fix | Delete
while ( $this->next_token() ) {
[432] Fix | Delete
if ( '#tag' !== $this->get_token_type() ) {
[433] Fix | Delete
continue;
[434] Fix | Delete
}
[435] Fix | Delete
[436] Fix | Delete
if ( ! $this->is_tag_closer() || $visit_closers ) {
[437] Fix | Delete
return true;
[438] Fix | Delete
}
[439] Fix | Delete
}
[440] Fix | Delete
[441] Fix | Delete
return false;
[442] Fix | Delete
}
[443] Fix | Delete
[444] Fix | Delete
if ( is_string( $query ) ) {
[445] Fix | Delete
$query = array( 'breadcrumbs' => array( $query ) );
[446] Fix | Delete
}
[447] Fix | Delete
[448] Fix | Delete
if ( ! is_array( $query ) ) {
[449] Fix | Delete
_doing_it_wrong(
[450] Fix | Delete
__METHOD__,
[451] Fix | Delete
__( 'Please pass a query array to this function.' ),
[452] Fix | Delete
'6.4.0'
[453] Fix | Delete
);
[454] Fix | Delete
return false;
[455] Fix | Delete
}
[456] Fix | Delete
[457] Fix | Delete
$needs_class = ( isset( $query['class_name'] ) && is_string( $query['class_name'] ) )
[458] Fix | Delete
? $query['class_name']
[459] Fix | Delete
: null;
[460] Fix | Delete
[461] Fix | Delete
if ( ! ( array_key_exists( 'breadcrumbs', $query ) && is_array( $query['breadcrumbs'] ) ) ) {
[462] Fix | Delete
while ( $this->next_token() ) {
[463] Fix | Delete
if ( '#tag' !== $this->get_token_type() ) {
[464] Fix | Delete
continue;
[465] Fix | Delete
}
[466] Fix | Delete
[467] Fix | Delete
if ( isset( $needs_class ) && ! $this->has_class( $needs_class ) ) {
[468] Fix | Delete
continue;
[469] Fix | Delete
}
[470] Fix | Delete
[471] Fix | Delete
if ( ! $this->is_tag_closer() || $visit_closers ) {
[472] Fix | Delete
return true;
[473] Fix | Delete
}
[474] Fix | Delete
}
[475] Fix | Delete
[476] Fix | Delete
return false;
[477] Fix | Delete
}
[478] Fix | Delete
[479] Fix | Delete
$breadcrumbs = $query['breadcrumbs'];
[480] Fix | Delete
$match_offset = isset( $query['match_offset'] ) ? (int) $query['match_offset'] : 1;
[481] Fix | Delete
[482] Fix | Delete
while ( $match_offset > 0 && $this->next_token() ) {
[483] Fix | Delete
if ( '#tag' !== $this->get_token_type() || $this->is_tag_closer() ) {
[484] Fix | Delete
continue;
[485] Fix | Delete
}
[486] Fix | Delete
[487] Fix | Delete
if ( isset( $needs_class ) && ! $this->has_class( $needs_class ) ) {
[488] Fix | Delete
continue;
[489] Fix | Delete
}
[490] Fix | Delete
[491] Fix | Delete
if ( $this->matches_breadcrumbs( $breadcrumbs ) && 0 === --$match_offset ) {
[492] Fix | Delete
return true;
[493] Fix | Delete
}
[494] Fix | Delete
}
[495] Fix | Delete
[496] Fix | Delete
return false;
[497] Fix | Delete
}
[498] Fix | Delete
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function