-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Interactivity API: Server Directive Processing #5953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
bb547e4
Code from GB
luisherranz 236eda2
Fix test pollution
luisherranz 7c95ee5
Fix tabs in multiline comments
luisherranz c084276
Improve state/config return msg and fix arg name
luisherranz 0fe3225
Remove unnecessary module registration
luisherranz e8daa1c
Fix typos
luisherranz c0f5804
Add missing @since statements
luisherranz eab8f28
Switch to null coalescing operator
luisherranz 19e454f
Replace array_push with $array[]
luisherranz 61d896f
Simplify conditional statement
luisherranz 84ea8fd
Replace null with empty array in state/config functions
luisherranz 0503eed
Add missing PHP 7 types
luisherranz 36e8adb
Remove default args passed to filter
luisherranz 2fef289
Add missing tests comments
luisherranz 4100309
Add @ticket to all the tests
luisherranz 8efcc12
Merge branch 'trunk' into wp-interactivity-api
luisherranz 69c6f78
Switch from static to global and move hooks/modules to settings
luisherranz 5462b18
Bail out if it finds an SVG or MathML tag
luisherranz 6dc2d42
Check for tags that don't visit their closer tag
luisherranz e9cb1fe
Use non-min script module versions
luisherranz 0534970
Add missing PHP 7 types
luisherranz 2bc2bea
Merge branch 'trunk' into wp-interactivity-api
luisherranz 553e8a4
Remove md5 in favor of array comparison
luisherranz ada6fe5
Use a hook to register the script modules so they can be overwritten …
luisherranz ee6e780
Omit curly brackets on string variable
luisherranz 1c73521
Make classes final
luisherranz 35ae36b
Fix typos
luisherranz a81d251
Add @uses to process_directives DocBlock
luisherranz 97d4c98
Don't return the result of array_pop
luisherranz 56a4d48
Don't return true on `has_and_visits_its_closer_tag` on null tag names
luisherranz 33fbc8d
Merge branch 'trunk' into wp-interactivity-api
luisherranz d19252b
Remove unnecessary file
luisherranz 49d5ebc
Remove more unnecessary files from wp-settings
luisherranz 264d0fb
Update WP_Interactivity_API_Directives_Processor
luisherranz 41ccbc1
Update WP_Interactivity_API
luisherranz c848fe2
Add tests for the new processors
luisherranz 6345e24
Support data-wp-interactive="myPlugin"
luisherranz 3b12a11
Add support for data_wp_context
luisherranz 4618663
Rename $start/$end to more descriptive names and add get_after_opener…
luisherranz ff61c7c
Fix some texts
luisherranz 71cda6e
Replace preg_replace with rtrim
luisherranz 4dbb4fe
Rename set_style_property to merge_style_property
luisherranz 330472c
Add json extension requirement to composer
luisherranz e0533e5
Fix some indentation issues
luisherranz e5b88fa
Replace array_push
luisherranz f010314
Use two block names in tests to make sure they render fine
luisherranz a2b4aae
Switch to render_block_{$this->name} filter
luisherranz c90d337
Add LanguageTool suggestion
luisherranz 8eec2f3
Add missing processors in @uses
luisherranz 8a1caa9
Try moving styles to a WP inline style
luisherranz 71d1918
Adapt interactivity detection to new schema
luisherranz 69afa13
Fix inline style
luisherranz 1bb9137
Change data-wp-router-region tests to check for the inline styles
luisherranz 30dc904
Checks for valid namespace characters in `data-wp-interactive`
luisherranz 9d21532
Replace underscores with hyphens
luisherranz a24af7d
Remove % in 0 values of CSS
luisherranz 3b189f7
Rename functions to use `get` and `print`
luisherranz ef1c9ae
Remove use of `@uses`
luisherranz 76dea4f
Don't use the primary color for the top loading bar
luisherranz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
244 changes: 244 additions & 0 deletions
244
src/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,244 @@ | ||
| <?php | ||
luisherranz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /** | ||
| * Interactivity API: WP_Interactivity_API_Directives_Processor class. | ||
| * | ||
| * @package WordPress | ||
| * @subpackage Interactivity API | ||
| * @since 6.5.0 | ||
| */ | ||
|
|
||
| /** | ||
| * Class used to iterate over the tags of an HTML string and help process the | ||
| * directive attributes. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
| */ | ||
| final class WP_Interactivity_API_Directives_Processor extends WP_HTML_Tag_Processor { | ||
| /** | ||
| * List of tags whose closer tag is not visited by the WP_HTML_Tag_Processor. | ||
| * | ||
| * @since 6.5.0 | ||
| * @var string[] | ||
| */ | ||
| const TAGS_THAT_DONT_VISIT_CLOSER_TAG = array( | ||
| 'SCRIPT', | ||
| 'IFRAME', | ||
| 'NOEMBED', | ||
| 'NOFRAMES', | ||
| 'STYLE', | ||
| 'TEXTAREA', | ||
| 'TITLE', | ||
| 'XMP', | ||
| ); | ||
|
|
||
| /** | ||
| * Returns the content between two balanced template tags. | ||
| * | ||
| * It positions the cursor in the closer tag of the balanced template tag, | ||
| * if it exists. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
swissspidy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * | ||
| * @return string|null The content between the current opener template tag and its matching closer tag or null if it | ||
| * doesn't find the matching closing tag or the current tag is not a template opener tag. | ||
| */ | ||
| public function get_content_between_balanced_template_tags() { | ||
| if ( 'TEMPLATE' !== $this->get_tag() ) { | ||
| return null; | ||
| } | ||
|
|
||
| $positions = $this->get_after_opener_tag_and_before_closer_tag_positions(); | ||
| if ( ! $positions ) { | ||
| return null; | ||
| } | ||
| list( $after_opener_tag, $before_closer_tag ) = $positions; | ||
|
|
||
| return substr( $this->html, $after_opener_tag, $before_closer_tag - $after_opener_tag ); | ||
| } | ||
|
|
||
| /** | ||
| * Sets the content between two balanced tags. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
| * | ||
| * @param string $new_content The string to replace the content between the matching tags. | ||
| * @return bool Whether the content was successfully replaced. | ||
| */ | ||
| public function set_content_between_balanced_tags( string $new_content ): bool { | ||
| $positions = $this->get_after_opener_tag_and_before_closer_tag_positions( true ); | ||
| if ( ! $positions ) { | ||
| return false; | ||
| } | ||
| list( $after_opener_tag, $before_closer_tag ) = $positions; | ||
|
|
||
| $this->lexical_updates[] = new WP_HTML_Text_Replacement( | ||
| $after_opener_tag, | ||
| $before_closer_tag - $after_opener_tag, | ||
| esc_html( $new_content ) | ||
| ); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Appends content after the closing tag of a template tag. | ||
| * | ||
| * It positions the cursor in the closer tag of the balanced template tag, | ||
| * if it exists. | ||
| * | ||
| * @access private | ||
| * | ||
| * @param string $new_content The string to append after the closing template tag. | ||
| * @return bool Whether the content was successfully appended. | ||
| */ | ||
| public function append_content_after_template_tag_closer( string $new_content ): bool { | ||
| if ( empty( $new_content ) || 'TEMPLATE' !== $this->get_tag() || ! $this->is_tag_closer() ) { | ||
| return false; | ||
| } | ||
|
|
||
| // Flushes any changes. | ||
| $this->get_updated_html(); | ||
|
|
||
| $bookmark = 'append_content_after_template_tag_closer'; | ||
| $this->set_bookmark( $bookmark ); | ||
| $after_closing_tag = $this->bookmarks[ $bookmark ]->start + $this->bookmarks[ $bookmark ]->length + 1; | ||
| $this->release_bookmark( $bookmark ); | ||
|
|
||
| // Appends the new content. | ||
| $this->lexical_updates[] = new WP_HTML_Text_Replacement( $after_closing_tag, 0, $new_content ); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the positions right after the opener tag and right before the closer | ||
| * tag in a balanced tag. | ||
| * | ||
| * By default, it positions the cursor in the closer tag of the balanced tag. | ||
| * If $rewind is true, it seeks back to the opener tag. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
| * | ||
| * @param bool $rewind Optional. Whether to seek back to the opener tag after finding the positions. Defaults to false. | ||
| * @return array|null Start and end byte position, or null when no balanced tag bookmarks. | ||
| */ | ||
| private function get_after_opener_tag_and_before_closer_tag_positions( bool $rewind = false ) { | ||
| // Flushes any changes. | ||
| $this->get_updated_html(); | ||
|
|
||
| $bookmarks = $this->get_balanced_tag_bookmarks(); | ||
| if ( ! $bookmarks ) { | ||
| return null; | ||
| } | ||
| list( $opener_tag, $closer_tag ) = $bookmarks; | ||
|
|
||
| $after_opener_tag = $this->bookmarks[ $opener_tag ]->start + $this->bookmarks[ $opener_tag ]->length + 1; | ||
| $before_closer_tag = $this->bookmarks[ $closer_tag ]->start; | ||
|
|
||
| if ( $rewind ) { | ||
| $this->seek( $opener_tag ); | ||
| } | ||
|
|
||
| $this->release_bookmark( $opener_tag ); | ||
| $this->release_bookmark( $closer_tag ); | ||
|
|
||
| return array( $after_opener_tag, $before_closer_tag ); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a pair of bookmarks for the current opener tag and the matching | ||
| * closer tag. | ||
| * | ||
| * It positions the cursor in the closer tag of the balanced tag, if it | ||
| * exists. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @return array|null A pair of bookmarks, or null if there's no matching closing tag. | ||
| */ | ||
| private function get_balanced_tag_bookmarks() { | ||
| static $i = 0; | ||
| $opener_tag = 'opener_tag_of_balanced_tag_' . ++$i; | ||
|
|
||
| $this->set_bookmark( $opener_tag ); | ||
| if ( ! $this->next_balanced_tag_closer_tag() ) { | ||
| $this->release_bookmark( $opener_tag ); | ||
| return null; | ||
| } | ||
|
|
||
| $closer_tag = 'closer_tag_of_balanced_tag_' . ++$i; | ||
| $this->set_bookmark( $closer_tag ); | ||
|
|
||
| return array( $opener_tag, $closer_tag ); | ||
| } | ||
|
|
||
| /** | ||
| * Finds the matching closing tag for an opening tag. | ||
| * | ||
| * When called while the processor is on an open tag, it traverses the HTML | ||
| * until it finds the matching closer tag, respecting any in-between content, | ||
| * including nested tags of the same name. Returns false when called on a | ||
| * closer tag, a tag that doesn't have a closer tag (void), a tag that | ||
| * doesn't visit the closer tag, or if no matching closing tag was found. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
| * | ||
| * @return bool Whether a matching closing tag was found. | ||
| */ | ||
| public function next_balanced_tag_closer_tag(): bool { | ||
| $depth = 0; | ||
| $tag_name = $this->get_tag(); | ||
|
|
||
| if ( ! $this->has_and_visits_its_closer_tag() ) { | ||
| return false; | ||
| } | ||
|
|
||
| while ( $this->next_tag( | ||
| array( | ||
| 'tag_name' => $tag_name, | ||
| 'tag_closers' => 'visit', | ||
| ) | ||
| ) ) { | ||
| if ( ! $this->is_tag_closer() ) { | ||
| ++$depth; | ||
| continue; | ||
| } | ||
|
|
||
| if ( 0 === $depth ) { | ||
| return true; | ||
| } | ||
luisherranz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| --$depth; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether the current tag has and will visit its matching closer tag. | ||
| * | ||
| * @since 6.5.0 | ||
| * | ||
| * @access private | ||
| * | ||
| * @return bool Whether the current tag has a closer tag. | ||
| */ | ||
| public function has_and_visits_its_closer_tag(): bool { | ||
| $tag_name = $this->get_tag(); | ||
|
|
||
| return null !== $tag_name && ( | ||
| ! WP_HTML_Processor::is_void( $tag_name ) && | ||
| ! in_array( $tag_name, self::TAGS_THAT_DONT_VISIT_CLOSER_TAG, true ) | ||
| ); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.