WP_Block_Parser::next_token() public WP 5.0.0
Scans the document from where we last left off and finds the next valid token to parse if it exists
Returns the type of the find: kind of find, block information, attributes
{} It's a method of the class: WP_Block_Parser{}
No Hooks.
Return
Array.
Usage
$WP_Block_Parser = new WP_Block_Parser(); $WP_Block_Parser->next_token();
Changelog
Since 5.0.0 | Introduced. |
Since 4.6.1 | fixed a bug in attribute parsing which caused catastrophic backtracking on invalid block comments |
Code of WP_Block_Parser::next_token() WP Block Parser::next token WP 5.6.2
function next_token() {
$matches = null;
/*
* aye the magic
* we're using a single RegExp to tokenize the block comment delimiters
* we're also using a trick here because the only difference between a
* block opener and a block closer is the leading `/` before `wp:` (and
* a closer has no attributes). we can trap them both and process the
* match back in PHP to see which one it was.
*/
$has_match = preg_match(
'/<!--\s+(?P<closer>\/)?wp:(?P<namespace>[a-z][a-z0-9_-]*\/)?(?P<name>[a-z][a-z0-9_-]*)\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P<void>\/)?-->/s',
$this->document,
$matches,
PREG_OFFSET_CAPTURE,
$this->offset
);
// if we get here we probably have catastrophic backtracking or out-of-memory in the PCRE.
if ( false === $has_match ) {
return array( 'no-more-tokens', null, null, null, null );
}
// we have no more tokens.
if ( 0 === $has_match ) {
return array( 'no-more-tokens', null, null, null, null );
}
list( $match, $started_at ) = $matches[0];
$length = strlen( $match );
$is_closer = isset( $matches['closer'] ) && -1 !== $matches['closer'][1];
$is_void = isset( $matches['void'] ) && -1 !== $matches['void'][1];
$namespace = $matches['namespace'];
$namespace = ( isset( $namespace ) && -1 !== $namespace[1] ) ? $namespace[0] : 'core/';
$name = $namespace . $matches['name'][0];
$has_attrs = isset( $matches['attrs'] ) && -1 !== $matches['attrs'][1];
/*
* Fun fact! It's not trivial in PHP to create "an empty associative array" since all arrays
* are associative arrays. If we use `array()` we get a JSON `[]`
*/
$attrs = $has_attrs
? json_decode( $matches['attrs'][0], /* as-associative */ true )
: $this->empty_attrs;
/*
* This state isn't allowed
* This is an error
*/
if ( $is_closer && ( $is_void || $has_attrs ) ) {
// we can ignore them since they don't hurt anything.
}
if ( $is_void ) {
return array( 'void-block', $name, $attrs, $started_at, $length );
}
if ( $is_closer ) {
return array( 'block-closer', $name, null, $started_at, $length );
}
return array( 'block-opener', $name, $attrs, $started_at, $length );
}