]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/shortcodes.php
Wordpress 3.7
[autoinstalls/wordpress.git] / wp-includes / shortcodes.php
index 2cc808ce481b36c11f36413d3f2a7d1ff6013713..dafb3a14051b975357154390f8e689265ce4523a 100644 (file)
@@ -48,7 +48,7 @@ $shortcode_tags = array();
  * There can only be one hook for each shortcode. Which means that if another
  * plugin has a similar shortcode, it will override yours or yours will override
  * theirs depending on which order the plugins are included and/or ran.
- * 
+ *
  * Simplest example of a shortcode tag using the API:
  *
  * <code>
@@ -127,6 +127,43 @@ function remove_all_shortcodes() {
        $shortcode_tags = array();
 }
 
+/**
+ * Whether a registered shortcode exists named $tag
+ *
+ * @since 3.6.0
+ *
+ * @global array $shortcode_tags
+ * @param string $tag
+ * @return boolean
+ */
+function shortcode_exists( $tag ) {
+       global $shortcode_tags;
+       return array_key_exists( $tag, $shortcode_tags );
+}
+
+/**
+ * Whether the passed content contains the specified shortcode
+ *
+ * @since 3.6.0
+ *
+ * @global array $shortcode_tags
+ * @param string $tag
+ * @return boolean
+ */
+function has_shortcode( $content, $tag ) {
+       if ( shortcode_exists( $tag ) ) {
+               preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
+               if ( empty( $matches ) )
+                       return false;
+
+               foreach ( $matches as $shortcode ) {
+                       if ( $tag === $shortcode[2] )
+                               return true;
+               }
+       }
+       return false;
+}
+
 /**
  * Search content for shortcodes and filter shortcodes through their hooks.
  *
@@ -148,7 +185,7 @@ function do_shortcode($content) {
                return $content;
 
        $pattern = get_shortcode_regex();
-       return preg_replace_callback('/'.$pattern.'/s', 'do_shortcode_tag', $content);
+       return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
 }
 
 /**
@@ -157,6 +194,15 @@ function do_shortcode($content) {
  * The regular expression combines the shortcode tags in the regular expression
  * in a regex class.
  *
+ * The regular expression contains 6 different sub matches to help with parsing.
+ *
+ * 1 - An extra [ to allow for escaping shortcodes with double [[]]
+ * 2 - The shortcode name
+ * 3 - The shortcode argument list
+ * 4 - The self closing /
+ * 5 - The content of a shortcode when it wraps some content.
+ * 6 - An extra ] to allow for escaping shortcodes with double [[]]
+ *
  * @since 2.5
  * @uses $shortcode_tags
  *
@@ -167,11 +213,42 @@ function get_shortcode_regex() {
        $tagnames = array_keys($shortcode_tags);
        $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
 
-       return '\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\1\])?';
+       // WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
+       // Also, see shortcode_unautop() and shortcode.js.
+       return
+                 '\\['                              // Opening bracket
+               . '(\\[?)'                           // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
+               . "($tagregexp)"                     // 2: Shortcode name
+               . '(?![\\w-])'                       // Not followed by word character or hyphen
+               . '('                                // 3: Unroll the loop: Inside the opening shortcode tag
+               .     '[^\\]\\/]*'                   // Not a closing bracket or forward slash
+               .     '(?:'
+               .         '\\/(?!\\])'               // A forward slash not followed by a closing bracket
+               .         '[^\\]\\/]*'               // Not a closing bracket or forward slash
+               .     ')*?'
+               . ')'
+               . '(?:'
+               .     '(\\/)'                        // 4: Self closing tag ...
+               .     '\\]'                          // ... and closing bracket
+               . '|'
+               .     '\\]'                          // Closing bracket
+               .     '(?:'
+               .         '('                        // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
+               .             '[^\\[]*+'             // Not an opening bracket
+               .             '(?:'
+               .                 '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
+               .                 '[^\\[]*+'         // Not an opening bracket
+               .             ')*+'
+               .         ')'
+               .         '\\[\\/\\2\\]'             // Closing shortcode tag
+               .     ')?'
+               . ')'
+               . '(\\]?)';                          // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
 }
 
 /**
  * Regular Expression callable for do_shortcode() for calling shortcode hook.
+ * @see get_shortcode_regex for details of the match array contents.
  *
  * @since 2.5
  * @access private
@@ -180,18 +257,23 @@ function get_shortcode_regex() {
  * @param array $m Regular expression match array
  * @return mixed False on failure.
  */
-function do_shortcode_tag($m) {
+function do_shortcode_tag( $m ) {
        global $shortcode_tags;
 
-       $tag = $m[1];
-       $attr = shortcode_parse_atts($m[2]);
+       // allow [[foo]] syntax for escaping a tag
+       if ( $m[1] == '[' && $m[6] == ']' ) {
+               return substr($m[0], 1, -1);
+       }
+
+       $tag = $m[2];
+       $attr = shortcode_parse_atts( $m[3] );
 
-       if ( isset($m[4]) ) {
+       if ( isset( $m[5] ) ) {
                // enclosing tag - extra parameter
-               return call_user_func($shortcode_tags[$tag], $attr, $m[4]);
+               return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, $m[5], $tag ) . $m[6];
        } else {
                // self-closing tag
-               return call_user_func($shortcode_tags[$tag], $attr);
+               return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, null,  $tag ) . $m[6];
        }
 }
 
@@ -204,7 +286,7 @@ function do_shortcode_tag($m) {
  *
  * @since 2.5
  *
- * @param string $text 
+ * @param string $text
  * @return array List of attributes and their value.
  */
 function shortcode_parse_atts($text) {
@@ -244,9 +326,10 @@ function shortcode_parse_atts($text) {
  *
  * @param array $pairs Entire list of supported attributes and their defaults.
  * @param array $atts User defined attributes in shortcode tag.
+ * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering
  * @return array Combined and filtered attribute list.
  */
-function shortcode_atts($pairs, $atts) {
+function shortcode_atts( $pairs, $atts, $shortcode = '' ) {
        $atts = (array)$atts;
        $out = array();
        foreach($pairs as $name => $default) {
@@ -255,6 +338,21 @@ function shortcode_atts($pairs, $atts) {
                else
                        $out[$name] = $default;
        }
+       /**
+        * Filter a shortcode's default attributes.
+        *
+        * If the third parameter of the shortcode_atts() function is present then this filter is available.
+        * The third parameter, $shortcode, is the name of the shortcode.
+        *
+        * @since 3.6.0
+        *
+        * @param array $out The output array of shortcode attributes.
+        * @param array $pairs The supported attributes and their defaults.
+        * @param array $atts The user defined shortcode attributes.
+        */
+       if ( $shortcode )
+               $out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts );
+
        return $out;
 }
 
@@ -275,9 +373,16 @@ function strip_shortcodes( $content ) {
 
        $pattern = get_shortcode_regex();
 
-       return preg_replace('/'.$pattern.'/s', '', $content);
+       return preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content );
 }
 
-add_filter('the_content', 'do_shortcode', 11); // AFTER wpautop() 
+function strip_shortcode_tag( $m ) {
+       // allow [[foo]] syntax for escaping a tag
+       if ( $m[1] == '[' && $m[6] == ']' ) {
+               return substr($m[0], 1, -1);
+       }
+
+       return $m[1] . $m[6];
+}
 
-?>
\ No newline at end of file
+add_filter('the_content', 'do_shortcode', 11); // AFTER wpautop()