2

i need to parse WordPress shortcode to array, in php, for example:

[parrent_shortcode attribute='1'  attribute2='a']
    [shortcode atrribute1=true attribute2=true]This is first content[/shortcode]
    [shortcode atrribute1=false]This is second content[/shortcode]
[/parrent_shortcode]

to become:

Array(
    [name] => 'parrent_shortcode'
    [atts] => Array(
        [attribute] => '1'
        [attribute2] => 'a'
    )
    [content] => Array(
        [child1] => Array(
            [name] => 'shortcode'
            [atts] => Array(
                [atrribute1] => true
                [attribute2] => true
            )
            [content] => 'This is first content'
        )
        [child2] => Array(
            [name] => 'shortcode'
            [atts] => Array(
                [atrribute1] => false
            )
            [content] => 'This is second content'
        )
    )
)

Also shortcodes can be without parrent wrapper and can be single (selfclosing) without content. Also attribute can have spaces in it.

I try to accomplish it using explode but ther are so many combinations..

2 Answers 2

7
function get_pattern( $text ) {
    $pattern = get_shortcode_regex();
    preg_match_all( "/$pattern/s", $text, $c );
    return $c;
}

function parse_atts( $content ) {
    $content = preg_match_all( '/([^ ]*)=(\'([^\']*)\'|\"([^\"]*)\"|([^ ]*))/', trim( $content ), $c );
    list( $dummy, $keys, $values ) = array_values( $c );
    $c = array();
    foreach ( $keys as $key => $value ) {
        $value = trim( $values[ $key ], "\"'" );
        $type = is_numeric( $value ) ? 'int' : 'string';
        $type = in_array( strtolower( $value ), array( 'true', 'false' ) ) ? 'bool' : $type;
        switch ( $type ) {
            case 'int': $value = (int) $value; break;
            case 'bool': $value = strtolower( $value ) == 'true'; break;
        }
        $c[ $keys[ $key ] ] = $value;
    }
    return $c;
}

function the_shortcodes( &$output, $text, $child = false ) {

    $patts = get_pattern( $text );
    $t = array_filter( get_pattern( $text ) );
    if ( ! empty( $t ) ) {
        list( $d, $d, $parents, $atts, $d, $contents ) = $patts;
        $out2 = array();
        $n = 0;
        foreach( $parents as $k=>$parent ) {
            ++$n;
            $name = $child ? 'child' . $n : $n;
            $t = array_filter( get_pattern( $contents[ $k ] ) );
            $t_s = the_shortcodes( $out2, $contents[ $k ], true );
            $output[ $name ] = array( 'name' => $parents[ $k ] );
            $output[ $name ]['atts'] = parse_atts( $atts[ $k ] );
            $output[ $name ]['original_content'] = $contents[ $k ];
            $output[ $name ]['content'] = ! empty( $t ) && ! empty( $t_s ) ? $t_s : $contents[ $k ];
        }
    }
    return array_values( $output );
}

usage :

$text = "[parrent_shortcode attribute='1' attribute2='a b c']
    [shortcode atrribute1=true attribute2=\"j'aime\"]This is first content[/shortcode]
    [shortcode atrribute1=false]This is [shortcode/] content[/shortcode]
[/parrent_shortcode]
";
$output = array();
$output = the_shortcodes( $output, $text );
var_dump( array_values( $output ) );

This echoes :

array (
  0 => 
  array (
    'name' => 'parrent_shortcode',
    'atts' => 
    array (
      'attribute' => 1,
      'attribute2' => 'a b c',
    ),
    'original_content' => '
    [shortcode atrribute1=true attribute2="j\'aime"]This is first content[/shortcode]
    [shortcode atrribute1=false]This is [shortcode/] content[/shortcode]
',
    'content' => 
    array (
      'child1' => 
      array (
        'name' => 'shortcode',
        'atts' => 
        array (
          'atrribute1' => true,
          'attribute2' => 'j\'aime',
        ),
        'original_content' => 'This is first content',
        'content' => 'This is first content',
      ),
      'child2' => 
      array (
        'name' => 'shortcode',
        'atts' => 
        array (
          'atrribute1' => false,
        ),
        'original_content' => 'This is [shortcode/] content',
        'content' => 
        array (
          0 => 
          array (
            'name' => 'shortcode',
            'atts' => 
            array (
            ),
            'original_content' => '',
            'content' => '',
          ),
        ),
      ),
    ),
  ),
)
Sign up to request clarification or add additional context in comments.

2 Comments

Hey this works great, although I did have issues with attribute values that contain an equals sign in the query string (e.g. YouTube videos). That ends up returning the following name/value: 'video_url="https://www.youtube.com/watch?v' => '3AGB8uovr9c', I can work around this for now, but suggestions welcome.
Update - I changed the regex to use the following and it seems to be working so far: '/([^ =]*)=([\'\"]?[^\"\']*[\'\"]?)/'
0

The shortcode API provides a function called do_shortcode() - Does that do what you want? The function is defined here: http://core.trac.wordpress.org/browser/tags/3.6.1/wp-includes/shortcodes.php#L181

Also, perhaps look at get_shortcode_regex() which is defined here: http://core.trac.wordpress.org/browser/tags/3.6.1/wp-includes/shortcodes.php#L211 You should be able to dig out the regex that parses the shortcode somehow.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.