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