@@ -417,6 +417,84 @@ public function next_tag( $query = null ) {
417417 return false ;
418418 }
419419
420+ /**
421+ * Returns the raw HTMl content inside a matched tag.
422+ *
423+ * @since 6.4.0
424+ *
425+ * @throws Exception When unable to allocate a bookmark for internal tracking of the open tag.
426+ *
427+ * @return string|null The inner HTML if available, else NULL.
428+ */
429+ public function get_inner_markup () {
430+ if ( null === $ this ->get_tag () ) {
431+ return null ;
432+ }
433+
434+ $ start = $ this ->current_token ;
435+ parent ::set_bookmark ( 'start ' );
436+ // @TODO: add after-pop hook to turn this into a constant boolean check.
437+ do {
438+ $ found_tag = $ this ->step ();
439+ } while ( $ found_tag && $ this ->state ->stack_of_open_elements ->contains_node ( $ start ) );
440+
441+ /*
442+ * If there's no tag to bookmark then it means the opened tag has no closing
443+ * and the rest of the document is contained within the inner HTML.
444+ */
445+ if ( ! $ found_tag ) {
446+ $ inner_html = $ this ->substr_bookmark ( 'after ' , 'start ' );
447+ parent ::release_bookmark ( 'start ' );
448+ } else {
449+ parent ::set_bookmark ( 'end ' );
450+ $ inner_html = $ this ->substr_bookmarks ( 'after ' , 'start ' , 'before ' , 'end ' );
451+ parent ::release_bookmark ( 'start ' );
452+ parent ::release_bookmark ( 'end ' );
453+ }
454+
455+ return $ inner_html ;
456+ }
457+
458+ /**
459+ * Returns the raw HTMl content inside a matched tag.
460+ *
461+ * @since 6.4.0
462+ *
463+ * @throws Exception When unable to allocate a bookmark for internal tracking of the open tag.
464+ *
465+ * @return string|null The inner HTML if available, else NULL.
466+ */
467+ public function get_outer_markup () {
468+ if ( null === $ this ->get_tag () ) {
469+ return null ;
470+ }
471+
472+ $ start = $ this ->current_token ;
473+ parent ::set_bookmark ( 'start ' );
474+ // @TODO: add after-pop hook to turn this into a constant boolean check.
475+ do {
476+ $ found_tag = $ this ->step ();
477+ } while ( $ found_tag && $ this ->state ->stack_of_open_elements ->contains_node ( $ start ) );
478+
479+ /*
480+ * If there's no tag to bookmark then it means the opened tag has no closing
481+ * and the rest of the document is contained within the inner HTML.
482+ */
483+ if ( ! $ found_tag ) {
484+ $ inner_html = $ this ->substr_bookmark ( 'before ' , 'start ' );
485+ } else {
486+ parent ::set_bookmark ( 'end ' );
487+ $ did_close = $ this ->get_tag () === $ start ->node_name && $ this ->is_tag_closer ();
488+ $ end_position = $ did_close ? 'after ' : 'before ' ;
489+ $ inner_html = $ this ->substr_bookmarks ( 'before ' , 'start ' , $ end_position , 'end ' );
490+ }
491+
492+ parent ::release_bookmark ( 'start ' );
493+ parent ::release_bookmark ( 'end ' );
494+
495+ return $ inner_html ;
496+ }
497+
420498 /**
421499 * Steps through the HTML document and stop at the next tag, if any.
422500 *
@@ -437,12 +515,9 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
437515 $ this ->state ->stack_of_open_elements ->pop ();
438516 }
439517
440- parent ::next_tag ( self ::VISIT_EVERYTHING );
441- }
442-
443- // Finish stepping when there are no more tokens in the document.
444- if ( null === $ this ->get_tag () ) {
445- return false ;
518+ if ( ! parent ::next_tag ( self ::VISIT_EVERYTHING ) ) {
519+ return false ;
520+ }
446521 }
447522
448523 $ this ->current_token = new WP_HTML_Token (
@@ -722,6 +797,42 @@ private function bookmark_tag() {
722797 return "{$ this ->bookmark_counter }" ;
723798 }
724799
800+ /**
801+ * Returns a substring of the input HTML document from a bookmark until the end.
802+ *
803+ * @since 6.4.0
804+ *
805+ * @param string $start_position "before" to clip before bookmark, "after" to clip after.
806+ * @param string $start Bookmark name at which to start clipping.
807+ * @return string Clipped substring of input HTMl document.
808+ */
809+ private function substr_bookmark ( $ start_position , $ start ) {
810+ $ start_bookmark = $ this ->bookmarks [ $ start ];
811+ $ start_offset = 'before ' === $ start_position ? $ start_bookmark ->start : $ start_bookmark ->end + 1 ;
812+
813+ return substr ( $ this ->html , $ start_offset );
814+ }
815+
816+ /**
817+ * Returns a substring of the input HTML document delimited by bookmarks.
818+ *
819+ * @since 6.4.0
820+ *
821+ * @param string $start_position "before" to clip before bookmark, "after" to clip after.
822+ * @param string $start Bookmark name at which to start clipping.
823+ * @param string $end_position "before" to clip before bookmark, "after" to clip after.
824+ * @param string $end Bookmark name at which to end clipping.
825+ * @return string Clipped substring of input HTMl document.
826+ */
827+ private function substr_bookmarks ( $ start_position , $ start , $ end_position , $ end ) {
828+ $ start_bookmark = $ this ->bookmarks [ $ start ];
829+ $ end_bookmark = $ this ->bookmarks [ $ end ];
830+ $ start_offset = 'before ' === $ start_position ? $ start_bookmark ->start : $ start_bookmark ->end + 1 ;
831+ $ end_offset = 'before ' === $ end_position ? $ end_bookmark ->start : $ end_bookmark ->end + 1 ;
832+
833+ return substr ( $ this ->html , $ start_offset , $ end_offset - $ start_offset );
834+ }
835+
725836 /*
726837 * HTML semantic overrides for Tag Processor
727838 */
0 commit comments