PageRenderTime 26ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/wordpress/wp-content/plugins/contact-form-7/includes/shortcodes.php

https://github.com/kronda/kronda
PHP | 420 lines | 310 code | 106 blank | 4 comment | 56 complexity | b1f2bfdf547356c59a2717dde1436eeb MD5 | raw file
  1. <?php
  2. class WPCF7_ShortcodeManager {
  3. private static $instance;
  4. private $shortcode_tags = array();
  5. // Taggs scanned at the last time of do_shortcode()
  6. private $scanned_tags = null;
  7. // Executing shortcodes (true) or just scanning (false)
  8. private $exec = true;
  9. private function __construct() {}
  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_shortcode( $tag, $func, $has_name = false ) {
  20. if ( ! is_callable( $func ) )
  21. return;
  22. $tags = array_filter( array_unique( (array) $tag ) );
  23. foreach ( $tags as $tag ) {
  24. $this->shortcode_tags[$tag] = array(
  25. 'function' => $func,
  26. 'has_name' => (boolean) $has_name );
  27. }
  28. }
  29. public function remove_shortcode( $tag ) {
  30. unset( $this->shortcode_tags[$tag] );
  31. }
  32. public function normalize_shortcode( $content ) {
  33. if ( empty( $this->shortcode_tags ) || ! is_array( $this->shortcode_tags ) )
  34. return $content;
  35. $pattern = $this->get_shortcode_regex();
  36. return preg_replace_callback( '/' . $pattern . '/s',
  37. array( $this, 'normalize_space_cb' ), $content );
  38. }
  39. private function normalize_space_cb( $m ) {
  40. // allow [[foo]] syntax for escaping a tag
  41. if ( $m[1] == '[' && $m[6] == ']' )
  42. return $m[0];
  43. $tag = $m[2];
  44. $attr = trim( preg_replace( '/[\r\n\t ]+/', ' ', $m[3] ) );
  45. $content = trim( $m[5] );
  46. $content = str_replace( "\n", '<WPPreserveNewline />', $content );
  47. $result = $m[1] . '[' . $tag
  48. . ( $attr ? ' ' . $attr : '' )
  49. . ( $m[4] ? ' ' . $m[4] : '' )
  50. . ']'
  51. . ( $content ? $content . '[/' . $tag . ']' : '' )
  52. . $m[6];
  53. return $result;
  54. }
  55. public function do_shortcode( $content, $exec = true ) {
  56. $this->exec = (bool) $exec;
  57. $this->scanned_tags = array();
  58. if ( empty( $this->shortcode_tags ) || ! is_array( $this->shortcode_tags ) )
  59. return $content;
  60. $pattern = $this->get_shortcode_regex();
  61. return preg_replace_callback( '/' . $pattern . '/s',
  62. array( $this, 'do_shortcode_tag' ), $content );
  63. }
  64. public function scan_shortcode( $content ) {
  65. $this->do_shortcode( $content, false );
  66. return $this->scanned_tags;
  67. }
  68. private function get_shortcode_regex() {
  69. $tagnames = array_keys( $this->shortcode_tags );
  70. $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
  71. return '(\[?)'
  72. . '\[(' . $tagregexp . ')(?:[\r\n\t ](.*?))?(?:[\r\n\t ](\/))?\]'
  73. . '(?:([^[]*?)\[\/\2\])?'
  74. . '(\]?)';
  75. }
  76. private function do_shortcode_tag( $m ) {
  77. // allow [[foo]] syntax for escaping a tag
  78. if ( $m[1] == '[' && $m[6] == ']' ) {
  79. return substr( $m[0], 1, -1 );
  80. }
  81. $tag = $m[2];
  82. $attr = $this->shortcode_parse_atts( $m[3] );
  83. $scanned_tag = array(
  84. 'type' => $tag,
  85. 'basetype' => trim( $tag, '*' ),
  86. 'name' => '',
  87. 'options' => array(),
  88. 'raw_values' => array(),
  89. 'values' => array(),
  90. 'pipes' => null,
  91. 'labels' => array(),
  92. 'attr' => '',
  93. 'content' => '' );
  94. if ( is_array( $attr ) ) {
  95. if ( is_array( $attr['options'] ) ) {
  96. if ( $this->shortcode_tags[$tag]['has_name'] && ! empty( $attr['options'] ) ) {
  97. $scanned_tag['name'] = array_shift( $attr['options'] );
  98. if ( ! wpcf7_is_name( $scanned_tag['name'] ) )
  99. return $m[0]; // Invalid name is used. Ignore this tag.
  100. }
  101. $scanned_tag['options'] = (array) $attr['options'];
  102. }
  103. $scanned_tag['raw_values'] = (array) $attr['values'];
  104. if ( WPCF7_USE_PIPE ) {
  105. $pipes = new WPCF7_Pipes( $scanned_tag['raw_values'] );
  106. $scanned_tag['values'] = $pipes->collect_befores();
  107. $scanned_tag['pipes'] = $pipes;
  108. } else {
  109. $scanned_tag['values'] = $scanned_tag['raw_values'];
  110. }
  111. $scanned_tag['labels'] = $scanned_tag['values'];
  112. } else {
  113. $scanned_tag['attr'] = $attr;
  114. }
  115. $scanned_tag['values'] = array_map( 'trim', $scanned_tag['values'] );
  116. $scanned_tag['labels'] = array_map( 'trim', $scanned_tag['labels'] );
  117. $content = trim( $m[5] );
  118. $content = preg_replace( "/<br[\r\n\t ]*\/?>$/m", '', $content );
  119. $scanned_tag['content'] = $content;
  120. $scanned_tag = apply_filters( 'wpcf7_form_tag', $scanned_tag, $this->exec );
  121. $this->scanned_tags[] = $scanned_tag;
  122. if ( $this->exec ) {
  123. $func = $this->shortcode_tags[$tag]['function'];
  124. return $m[1] . call_user_func( $func, $scanned_tag ) . $m[6];
  125. } else {
  126. return $m[0];
  127. }
  128. }
  129. private function shortcode_parse_atts( $text ) {
  130. $atts = array( 'options' => array(), 'values' => array() );
  131. $text = preg_replace( "/[\x{00a0}\x{200b}]+/u", " ", $text );
  132. $text = stripcslashes( trim( $text ) );
  133. $pattern = '%^([-+*=0-9a-zA-Z:.!?#$&@_/|\%\r\n\t ]*?)((?:[\r\n\t ]*"[^"]*"|[\r\n\t ]*\'[^\']*\')*)$%';
  134. if ( preg_match( $pattern, $text, $match ) ) {
  135. if ( ! empty( $match[1] ) ) {
  136. $atts['options'] = preg_split( '/[\r\n\t ]+/', trim( $match[1] ) );
  137. }
  138. if ( ! empty( $match[2] ) ) {
  139. preg_match_all( '/"[^"]*"|\'[^\']*\'/', $match[2], $matched_values );
  140. $atts['values'] = wpcf7_strip_quote_deep( $matched_values[0] );
  141. }
  142. } else {
  143. $atts = $text;
  144. }
  145. return $atts;
  146. }
  147. }
  148. function wpcf7_add_shortcode( $tag, $func, $has_name = false ) {
  149. $manager = WPCF7_ShortcodeManager::get_instance();
  150. return $manager->add_shortcode( $tag, $func, $has_name );
  151. }
  152. function wpcf7_remove_shortcode( $tag ) {
  153. $manager = WPCF7_ShortcodeManager::get_instance();
  154. return $manager->remove_shortcode( $tag );
  155. }
  156. function wpcf7_do_shortcode( $content ) {
  157. $manager = WPCF7_ShortcodeManager::get_instance();
  158. return $manager->do_shortcode( $content );
  159. }
  160. class WPCF7_Shortcode {
  161. public $type;
  162. public $basetype;
  163. public $name = '';
  164. public $options = array();
  165. public $raw_values = array();
  166. public $values = array();
  167. public $pipes;
  168. public $labels = array();
  169. public $attr = '';
  170. public $content = '';
  171. public function __construct( $tag ) {
  172. foreach ( $tag as $key => $value ) {
  173. if ( property_exists( __CLASS__, $key ) )
  174. $this->{$key} = $value;
  175. }
  176. }
  177. public function is_required() {
  178. return ( '*' == substr( $this->type, -1 ) );
  179. }
  180. public function has_option( $opt ) {
  181. $pattern = sprintf( '/^%s(:.+)?$/i', preg_quote( $opt, '/' ) );
  182. return (bool) preg_grep( $pattern, $this->options );
  183. }
  184. public function get_option( $opt, $pattern = '', $single = false ) {
  185. $preset_patterns = array(
  186. 'date' => '([0-9]{4}-[0-9]{2}-[0-9]{2}|today(.*))',
  187. 'int' => '[0-9]+',
  188. 'signed_int' => '-?[0-9]+',
  189. 'class' => '[-0-9a-zA-Z_]+',
  190. 'id' => '[-0-9a-zA-Z_]+' );
  191. if ( isset( $preset_patterns[$pattern] ) )
  192. $pattern = $preset_patterns[$pattern];
  193. if ( '' == $pattern )
  194. $pattern = '.+';
  195. $pattern = sprintf( '/^%s:%s$/i', preg_quote( $opt, '/' ), $pattern );
  196. if ( $single ) {
  197. $matches = $this->get_first_match_option( $pattern );
  198. if ( ! $matches )
  199. return false;
  200. return substr( $matches[0], strlen( $opt ) + 1 );
  201. } else {
  202. $matches_a = $this->get_all_match_options( $pattern );
  203. if ( ! $matches_a )
  204. return false;
  205. $results = array();
  206. foreach ( $matches_a as $matches )
  207. $results[] = substr( $matches[0], strlen( $opt ) + 1 );
  208. return $results;
  209. }
  210. }
  211. public function get_id_option() {
  212. return $this->get_option( 'id', 'id', true );
  213. }
  214. public function get_class_option( $default = '' ) {
  215. if ( is_string( $default ) )
  216. $default = explode( ' ', $default );
  217. $options = array_merge(
  218. (array) $default,
  219. (array) $this->get_option( 'class', 'class' ) );
  220. $options = array_filter( array_unique( $options ) );
  221. return implode( ' ', $options );
  222. }
  223. public function get_size_option( $default = '' ) {
  224. $matches_a = $this->get_all_match_options( '%^([0-9]*)/[0-9]*$%' );
  225. foreach ( (array) $matches_a as $matches ) {
  226. if ( isset( $matches[1] ) && '' !== $matches[1] )
  227. return $matches[1];
  228. }
  229. return $default;
  230. }
  231. public function get_maxlength_option( $default = '' ) {
  232. $matches_a = $this->get_all_match_options(
  233. '%^(?:[0-9]*x?[0-9]*)?/([0-9]+)$%' );
  234. foreach ( (array) $matches_a as $matches ) {
  235. if ( isset( $matches[1] ) && '' !== $matches[1] )
  236. return $matches[1];
  237. }
  238. return $default;
  239. }
  240. public function get_cols_option( $default = '' ) {
  241. $matches_a = $this->get_all_match_options(
  242. '%^([0-9]*)x([0-9]*)(?:/[0-9]+)?$%' );
  243. foreach ( (array) $matches_a as $matches ) {
  244. if ( isset( $matches[1] ) && '' !== $matches[1] )
  245. return $matches[1];
  246. }
  247. return $default;
  248. }
  249. public function get_rows_option( $default = '' ) {
  250. $matches_a = $this->get_all_match_options(
  251. '%^([0-9]*)x([0-9]*)(?:/[0-9]+)?$%' );
  252. foreach ( (array) $matches_a as $matches ) {
  253. if ( isset( $matches[2] ) && '' !== $matches[2] )
  254. return $matches[2];
  255. }
  256. return $default;
  257. }
  258. public function get_date_option( $opt ) {
  259. $option = $this->get_option( $opt, 'date', true );
  260. if ( preg_match( '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $option ) ) {
  261. return $option;
  262. }
  263. if ( preg_match( '/^today(?:([+-][0-9]+)([a-z]*))?/', $option, $matches ) ) {
  264. $number = isset( $matches[1] ) ? (int) $matches[1] : 0;
  265. $unit = isset( $matches[2] ) ? $matches[2] : '';
  266. if ( ! preg_match( '/^(day|month|year|week)s?$/', $unit ) ) {
  267. $unit = 'days';
  268. }
  269. $date = gmdate( 'Y-m-d',
  270. strtotime( sprintf( 'today %1$s %2$s', $number, $unit ) ) );
  271. return $date;
  272. }
  273. return false;
  274. }
  275. public function get_default_option() {
  276. $options = (array) $this->get_option( 'default' );
  277. if ( empty( $options ) ) {
  278. return false;
  279. }
  280. foreach ( $options as $opt ) {
  281. $opt = sanitize_key( $opt );
  282. if ( 'user_' == substr( $opt, 0, 5 ) && is_user_logged_in() ) {
  283. $primary_props = array( 'user_login', 'user_email', 'user_url' );
  284. $opt = in_array( $opt, $primary_props ) ? $opt : substr( $opt, 5 );
  285. $user = wp_get_current_user();
  286. $user_prop = $user->get( $opt );
  287. if ( ! empty( $user_prop ) ) {
  288. return $user_prop;
  289. }
  290. }
  291. }
  292. return false;
  293. }
  294. public function get_data_option( $args = '' ) {
  295. $options = (array) $this->get_option( 'data' );
  296. return apply_filters( 'wpcf7_form_tag_data_option', null, $options, $args );
  297. }
  298. public function get_first_match_option( $pattern ) {
  299. foreach( (array) $this->options as $option ) {
  300. if ( preg_match( $pattern, $option, $matches ) )
  301. return $matches;
  302. }
  303. return false;
  304. }
  305. public function get_all_match_options( $pattern ) {
  306. $result = array();
  307. foreach( (array) $this->options as $option ) {
  308. if ( preg_match( $pattern, $option, $matches ) )
  309. $result[] = $matches;
  310. }
  311. return $result;
  312. }
  313. }
  314. ?>