WPCF7_FormTagsManager

The Contact Form 7 WPCF7 FormTagsManager class.

Defined (1)

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

/includes/form-tags-manager.php  
  1. class WPCF7_FormTagsManager { 
  2.  
  3. private static $instance; 
  4.  
  5. private $tag_types = array(); 
  6. private $scanned_tags = null; // Tags scanned at the last time of scan() 
  7.  
  8. private function __construct() {} 
  9.  
  10. public static function get_instance() { 
  11. if ( empty( self::$instance ) ) { 
  12. self::$instance = new self; 
  13.  
  14. return self::$instance; 
  15.  
  16. public function get_scanned_tags() { 
  17. return $this->scanned_tags; 
  18.  
  19. public function add( $tag, $func, $features = '' ) { 
  20. if ( ! is_callable( $func ) ) { 
  21. return; 
  22.  
  23. if ( true === $features ) { // for back-compat 
  24. $features = array( 'name-attr' => true ); 
  25.  
  26. $features = wp_parse_args( $features, array() ); 
  27.  
  28. $tags = array_filter( array_unique( (array) $tag ) ); 
  29.  
  30. foreach ( $tags as $tag ) { 
  31. $tag = $this->sanitize_tag_type( $tag ); 
  32.  
  33. if ( ! $this->tag_type_exists( $tag ) ) { 
  34. $this->tag_types[$tag] = array( 
  35. 'function' => $func,  
  36. 'features' => $features,  
  37. ); 
  38.  
  39. public function tag_type_exists( $tag ) { 
  40. return isset( $this->tag_types[$tag] ); 
  41.  
  42. public function tag_type_supports( $tag, $feature ) { 
  43. if ( isset( $this->tag_types[$tag]['features'] ) ) { 
  44. return ! empty( $this->tag_types[$tag]['features'][$feature] ); 
  45.  
  46. return false; 
  47.  
  48. private function sanitize_tag_type( $tag ) { 
  49. $tag = preg_replace( '/[^a-zA-Z0-9_*]+/', '_', $tag ); 
  50. $tag = rtrim( $tag, '_' ); 
  51. $tag = strtolower( $tag ); 
  52. return $tag; 
  53.  
  54. public function remove( $tag ) { 
  55. unset( $this->tag_types[$tag] ); 
  56.  
  57. public function normalize( $content ) { 
  58. if ( empty( $this->tag_types ) ) { 
  59. return $content; 
  60.  
  61. $content = preg_replace_callback( 
  62. '/' . $this->tag_regex() . '/s',  
  63. array( $this, 'normalize_callback' ),  
  64. $content ); 
  65.  
  66. return $content; 
  67.  
  68. private function normalize_callback( $m ) { 
  69. // allow [[foo]] syntax for escaping a tag 
  70. if ( $m[1] == '[' && $m[6] == ']' ) { 
  71. return $m[0]; 
  72.  
  73. $tag = $m[2]; 
  74.  
  75. $attr = trim( preg_replace( '/[\r\n\t ]+/', ' ', $m[3] ) ); 
  76. $attr = strtr( $attr, array( '<' => '<', '>' => '>' ) ); 
  77.  
  78. $content = trim( $m[5] ); 
  79. $content = str_replace( "\n", '<WPPreserveNewline />', $content ); 
  80.  
  81. $result = $m[1] . '[' . $tag 
  82. . ( $attr ? ' ' . $attr : '' ) 
  83. . ( $m[4] ? ' ' . $m[4] : '' ) 
  84. . ']' 
  85. . ( $content ? $content . '[/' . $tag . ']' : '' ) 
  86. . $m[6]; 
  87.  
  88. return $result; 
  89.  
  90. public function replace_all( $content ) { 
  91. return $this->scan( $content, true ); 
  92.  
  93. public function scan( $content, $replace = false ) { 
  94. $this->scanned_tags = array(); 
  95.  
  96. if ( empty( $this->tag_types ) ) { 
  97. if ( $replace ) { 
  98. return $content; 
  99. } else { 
  100. return $this->scanned_tags; 
  101.  
  102. if ( $replace ) { 
  103. $content = preg_replace_callback( 
  104. '/' . $this->tag_regex() . '/s',  
  105. array( $this, 'replace_callback' ),  
  106. $content ); 
  107.  
  108. return $content; 
  109. } else { 
  110. preg_replace_callback( 
  111. '/' . $this->tag_regex() . '/s',  
  112. array( $this, 'scan_callback' ),  
  113. $content ); 
  114.  
  115. return $this->scanned_tags; 
  116.  
  117. public function filter( $content, $cond ) { 
  118. if ( is_array( $content ) ) { 
  119. $tags = $content; 
  120. } elseif ( is_string( $content ) ) { 
  121. $tags = $this->scan( $content ); 
  122. } else { 
  123. $tags = $this->scanned_tags; 
  124.  
  125. if ( empty( $tags ) ) { 
  126. return array(); 
  127.  
  128. if ( ! is_array( $cond ) || empty( $cond ) ) { 
  129. return $tags; 
  130.  
  131. for ( $i = 0, $size = count( $tags ); $i < $size; $i++ ) { 
  132.  
  133. if ( isset( $cond['type'] ) ) { 
  134. if ( is_string( $cond['type'] ) && ! empty( $cond['type'] ) ) { 
  135. if ( $tags[$i]['type'] != $cond['type'] ) { 
  136. unset( $tags[$i] ); 
  137. continue; 
  138. } elseif ( is_array( $cond['type'] ) ) { 
  139. if ( ! in_array( $tags[$i]['type'], $cond['type'] ) ) { 
  140. unset( $tags[$i] ); 
  141. continue; 
  142.  
  143. if ( isset( $cond['name'] ) ) { 
  144. if ( is_string( $cond['name'] ) && ! empty( $cond['name'] ) ) { 
  145. if ( $tags[$i]['name'] != $cond['name'] ) { 
  146. unset ( $tags[$i] ); 
  147. continue; 
  148. } elseif ( is_array( $cond['name'] ) ) { 
  149. if ( ! in_array( $tags[$i]['name'], $cond['name'] ) ) { 
  150. unset( $tags[$i] ); 
  151. continue; 
  152.  
  153. return array_values( $tags ); 
  154.  
  155. private function tag_regex() { 
  156. $tagnames = array_keys( $this->tag_types ); 
  157. $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 
  158.  
  159. return '(\[?)' 
  160. . '\[(' . $tagregexp . ')(?:[\r\n\t ](.*?))?(?:[\r\n\t ](\/))?\]' 
  161. . '(?:([^[]*?)\[\/\2\])?' 
  162. . '(\]?)'; 
  163.  
  164. private function replace_callback( $m ) { 
  165. return $this->scan_callback( $m, true ); 
  166.  
  167. private function scan_callback( $m, $replace = false ) { 
  168. // allow [[foo]] syntax for escaping a tag 
  169. if ( $m[1] == '[' && $m[6] == ']' ) { 
  170. return substr( $m[0], 1, -1 ); 
  171.  
  172. $tag = $m[2]; 
  173. $attr = $this->parse_atts( $m[3] ); 
  174.  
  175. $scanned_tag = array( 
  176. 'type' => $tag,  
  177. 'basetype' => trim( $tag, '*' ),  
  178. 'name' => '',  
  179. 'options' => array(),  
  180. 'raw_values' => array(),  
  181. 'values' => array(),  
  182. 'pipes' => null,  
  183. 'labels' => array(),  
  184. 'attr' => '',  
  185. 'content' => '',  
  186. ); 
  187.  
  188. if ( is_array( $attr ) ) { 
  189. if ( is_array( $attr['options'] ) ) { 
  190. if ( $this->tag_type_supports( $tag, 'name-attr' ) 
  191. && ! empty( $attr['options'] ) ) { 
  192. $scanned_tag['name'] = array_shift( $attr['options'] ); 
  193.  
  194. if ( ! wpcf7_is_name( $scanned_tag['name'] ) ) { 
  195. return $m[0]; // Invalid name is used. Ignore this tag. 
  196.  
  197. $scanned_tag['options'] = (array) $attr['options']; 
  198.  
  199. $scanned_tag['raw_values'] = (array) $attr['values']; 
  200.  
  201. if ( WPCF7_USE_PIPE ) { 
  202. $pipes = new WPCF7_Pipes( $scanned_tag['raw_values'] ); 
  203. $scanned_tag['values'] = $pipes->collect_befores(); 
  204. $scanned_tag['pipes'] = $pipes; 
  205. } else { 
  206. $scanned_tag['values'] = $scanned_tag['raw_values']; 
  207.  
  208. $scanned_tag['labels'] = $scanned_tag['values']; 
  209.  
  210. } else { 
  211. $scanned_tag['attr'] = $attr; 
  212.  
  213. $scanned_tag['values'] = array_map( 'trim', $scanned_tag['values'] ); 
  214. $scanned_tag['labels'] = array_map( 'trim', $scanned_tag['labels'] ); 
  215.  
  216. $content = trim( $m[5] ); 
  217. $content = preg_replace( "/<br[\r\n\t ]*\/?>$/m", '', $content ); 
  218. $scanned_tag['content'] = $content; 
  219.  
  220. $scanned_tag = apply_filters( 'wpcf7_form_tag', $scanned_tag, $replace ); 
  221.  
  222. $this->scanned_tags[] = $scanned_tag; 
  223.  
  224. if ( $replace ) { 
  225. $func = $this->tag_types[$tag]['function']; 
  226. return $m[1] . call_user_func( $func, $scanned_tag ) . $m[6]; 
  227. } else { 
  228. return $m[0]; 
  229.  
  230. private function parse_atts( $text ) { 
  231. $atts = array( 'options' => array(), 'values' => array() ); 
  232. $text = preg_replace( "/[\x{00a0}\x{200b}]+/u", " ", $text ); 
  233. $text = stripcslashes( trim( $text ) ); 
  234.  
  235. $pattern = '%^([-+*=0-9a-zA-Z:.!?#$&@_/|\%\r\n\t ]*?)((?:[\r\n\t ]*"[^"]*"|[\r\n\t ]*\'[^\']*\')*)$%'; 
  236.  
  237. if ( preg_match( $pattern, $text, $match ) ) { 
  238. if ( ! empty( $match[1] ) ) { 
  239. $atts['options'] = preg_split( '/[\r\n\t ]+/', trim( $match[1] ) ); 
  240.  
  241. if ( ! empty( $match[2] ) ) { 
  242. preg_match_all( '/"[^"]*"|\'[^\']*\'/', $match[2], $matched_values ); 
  243. $atts['values'] = wpcf7_strip_quote_deep( $matched_values[0] ); 
  244. } else { 
  245. $atts = $text; 
  246.  
  247. return $atts;