force_balance_tags

Balances tags of string using a modified stack.

Description

(string) force_balance_tags( (string) $text ); 

Returns (string)

Balanced text.

Parameters (1)

0. $text (string)
Text to be balanced.

Usage

  1. if ( !function_exists( 'force_balance_tags' ) ) { 
  2. require_once ABSPATH . WPINC . '/formatting.php'; 
  3.  
  4. // Text to be balanced. 
  5. $text = ''; 
  6.  
  7. // NOTICE! Understand what this does before running. 
  8. $result = force_balance_tags($text); 
  9.  

Defined (1)

The function is defined in the following location(s).

/wp-includes/formatting.php  
  1. function force_balance_tags( $text ) { 
  2. $tagstack = array(); 
  3. $stacksize = 0; 
  4. $tagqueue = ''; 
  5. $newtext = ''; 
  6. // Known single-entity/self-closing tags 
  7. $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' ); 
  8. // Tags that can be immediately nested within themselves 
  9. $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' ); 
  10.  
  11. // WP bug fix for comments - in case you REALLY meant to type '< !--' 
  12. $text = str_replace('< !--', '< !--', $text); 
  13. // WP bug fix for LOVE <3 (and other situations with '<' before a number) 
  14. $text = preg_replace('#<([0-9]{1})#', '<$1', $text); 
  15.  
  16. while ( preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $regex) ) { 
  17. $newtext .= $tagqueue; 
  18.  
  19. $i = strpos($text, $regex[0]); 
  20. $l = strlen($regex[0]); 
  21.  
  22. // clear the shifter 
  23. $tagqueue = ''; 
  24. // Pop or Push 
  25. if ( isset($regex[1][0]) && '/' == $regex[1][0] ) { // End Tag 
  26. $tag = strtolower(substr($regex[1], 1)); 
  27. // if too many closing tags 
  28. if ( $stacksize <= 0 ) { 
  29. $tag = ''; 
  30. // or close to be safe $tag = '/' . $tag; 
  31. // if stacktop value = tag close value then pop 
  32. elseif ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag 
  33. $tag = '</' . $tag . '>'; // Close Tag 
  34. // Pop 
  35. array_pop( $tagstack ); 
  36. $stacksize--; 
  37. } else { // closing tag not at top, search for it 
  38. for ( $j = $stacksize-1; $j >= 0; $j-- ) { 
  39. if ( $tagstack[$j] == $tag ) { 
  40. // add tag to tagqueue 
  41. for ( $k = $stacksize-1; $k >= $j; $k--) { 
  42. $tagqueue .= '</' . array_pop( $tagstack ) . '>'; 
  43. $stacksize--; 
  44. break; 
  45. $tag = ''; 
  46. } else { // Begin Tag 
  47. $tag = strtolower($regex[1]); 
  48.  
  49. // Tag Cleaning 
  50.  
  51. // If it's an empty tag "< >", do nothing 
  52. if ( '' == $tag ) { 
  53. // do nothing 
  54. // ElseIf it presents itself as a self-closing tag... 
  55. elseif ( substr( $regex[2], -1 ) == '/' ) { 
  56. // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and 
  57. // immediately close it with a closing tag (the tag will encapsulate no text as a result) 
  58. if ( ! in_array( $tag, $single_tags ) ) 
  59. $regex[2] = trim( substr( $regex[2], 0, -1 ) ) . "></$tag"; 
  60. // ElseIf it's a known single-entity tag but it doesn't close itself, do so 
  61. elseif ( in_array($tag, $single_tags) ) { 
  62. $regex[2] .= '/'; 
  63. // Else it's not a single-entity tag 
  64. else { 
  65. // If the top of the stack is the same as the tag we want to push, close previous tag 
  66. if ( $stacksize > 0 && !in_array($tag, $nestable_tags) && $tagstack[$stacksize - 1] == $tag ) { 
  67. $tagqueue = '</' . array_pop( $tagstack ) . '>'; 
  68. $stacksize--; 
  69. $stacksize = array_push( $tagstack, $tag ); 
  70.  
  71. // Attributes 
  72. $attributes = $regex[2]; 
  73. if ( ! empty( $attributes ) && $attributes[0] != '>' ) 
  74. $attributes = ' ' . $attributes; 
  75.  
  76. $tag = '<' . $tag . $attributes . '>'; 
  77. //If already queuing a close tag, then put this tag on, too 
  78. if ( !empty($tagqueue) ) { 
  79. $tagqueue .= $tag; 
  80. $tag = ''; 
  81. $newtext .= substr($text, 0, $i) . $tag; 
  82. $text = substr($text, $i + $l); 
  83.  
  84. // Clear Tag Queue 
  85. $newtext .= $tagqueue; 
  86.  
  87. // Add Remaining text 
  88. $newtext .= $text; 
  89.  
  90. // Empty Stack 
  91. while( $x = array_pop($tagstack) ) 
  92. $newtext .= '</' . $x . '>'; // Add remaining tags to close 
  93.  
  94. // WP fix for the bug with HTML comments 
  95. $newtext = str_replace("< !--", "<!--", $newtext); 
  96. $newtext = str_replace("< !--", "< !--", $newtext); 
  97.  
  98. return $newtext;