WP_HTML_Tag_Processor::class_name_updates_to_attributes_updates()

In this article

This function’s access is marked private. This means it is not intended for use by plugin or theme developers, only in other core functions. It is listed here for completeness. Use WP_HTML_Tag_Processor::$lexical_updates instead.

Converts class name updates into tag attributes updates (they are accumulated in different data formats for performance).

Description

See also

  • WP_HTML_Tag_Processor::$lexical_updates
  • WP_HTML_Tag_Processor::$classname_updates

Source

				$attribute_end              = $end_quote_at + 1;
				$this->bytes_already_parsed = $attribute_end;
				break;

			default:
				$value_start                = $this->bytes_already_parsed;
				$value_length               = strcspn( $this->html, "> \t\f\r\n", $value_start );
				$attribute_end              = $value_start + $value_length;
				$this->bytes_already_parsed = $attribute_end;
		}
	} else {
		$value_start   = $this->bytes_already_parsed;
		$value_length  = 0;
		$attribute_end = $attribute_start + $name_length;
	}

	if ( $attribute_end >= $doc_length ) {
		$this->parser_state = self::STATE_INCOMPLETE_INPUT;

		return false;
	}

	if ( $this->is_closing_tag ) {
		return true;
	}

	/*
	 * > There must never be two or more attributes on
	 * > the same start tag whose names are an ASCII
	 * > case-insensitive match for each other.
	 *     - HTML 5 spec
	 *
	 * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive
	 */
	$comparable_name = strtolower( $attribute_name );

	// If an attribute is listed many times, only use the first declaration and ignore the rest.
	if ( ! isset( $this->attributes[ $comparable_name ] ) ) {
		$this->attributes[ $comparable_name ] = new WP_HTML_Attribute_Token(
			$attribute_name,
			$value_start,
			$value_length,
			$attribute_start,
			$attribute_end - $attribute_start,
			! $has_value
		);

		return true;
	}

	/*
	 * Track the duplicate attributes so if we remove it, all disappear together.
	 *
	 * While `$this->duplicated_attributes` could always be stored as an `array()`,
	 * which would simplify the logic here, storing a `null` and only allocating
	 * an array when encountering duplicates avoids needless allocations in the
	 * normative case of parsing tags with no duplicate attributes.
	 */
	$duplicate_span = new WP_HTML_Span( $attribute_start, $attribute_end - $attribute_start );
	if ( null === $this->duplicate_attributes ) {
		$this->duplicate_attributes = array( $comparable_name => array( $duplicate_span ) );
	} elseif ( ! isset( $this->duplicate_attributes[ $comparable_name ] ) ) {
		$this->duplicate_attributes[ $comparable_name ] = array( $duplicate_span );
	} else {
		$this->duplicate_attributes[ $comparable_name ][] = $duplicate_span;
	}

	return true;
}

/**
 * Move the internal cursor past any immediate successive whitespace.
 *
 * @since 6.2.0
 */
private function skip_whitespace(): void {
	$this->bytes_already_parsed += strspn( $this->html, " \t\f\r\n", $this->bytes_already_parsed );
}

/**
 * Applies attribute updates and cleans up once a tag is fully parsed.
 *
 * @since 6.2.0
 */
private function after_tag(): void {
	/*
	 * There could be lexical updates enqueued for an attribute that
	 * also exists on the next tag. In order to avoid conflating the
	 * attributes across the two tags, lexical updates with names
	 * need to be flushed to raw lexical updates.
	 */
	$this->class_name_updates_to_attributes_updates();

	/*
	 * Purge updates if there are too many. The actual count isn't
	 * scientific, but a few values from 100 to a few thousand were
	 * tests to find a practically-useful limit.
	 *
	 * If the update queue grows too big, then the Tag Processor
	 * will spend more time iterating through them and lose the
	 * efficiency gains of deferring applying them.
	 */
	if ( 1000 < count( $this->lexical_updates ) ) {
		$this->get_updated_html();
	}

	foreach ( $this->lexical_updates as $name => $update ) {
		/*
		 * Any updates appearing after the cursor should be applied
		 * before proceeding, otherwise they may be overlooked.
		 */
		if ( $update->start >= $this->bytes_already_parsed ) {
			$this->get_updated_html();
			break;
		}

		if ( is_int( $name ) ) {
			continue;
		}

		$this->lexical_updates[] = $update;
		unset( $this->lexical_updates[ $name ] );
	}

	$this->token_starts_at          = null;
	$this->token_length             = null;
	$this->tag_name_starts_at       = null;
	$this->tag_name_length          = null;
	$this->text_starts_at           = 0;
	$this->text_length              = 0;
	$this->is_closing_tag           = null;
	$this->attributes               = array();

Changelog

VersionDescription
6.2.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.