3

The nested shortcodes won't parse correctly:

[row]
    [col size="6"]...[/col]
    [col size="6"]
        [row]
            [col size="6"]...[/col]
            [col size="6"]...[/col]
        [/row]
    [/col]
[/row]

From the WordPress documentation, I understand that it is a WordPress shortcodes limitation. Is it still possible to get it work?

Edit: Here's my shortcodes code, it works fine if its not nested (ie., row shortcode is not used inside the col shortcode).

add_shortcode( 'row', 'row_cb' );
function row_cb( $atts, $content = null ) {             
        $output = '';
        $output .= '<div class="row">';
        $output .= do_shortcode( $content );        
        $output .= '</div>';

        return $output; 
}

add_shortcode( 'col', 'col_cb' );
function col_cb( $atts, $content = null ) {     
    extract( shortcode_atts( array(
            'size'  => '',
        ), $atts ) );


    $output = '';
    $output .= '<div class="col">';
    $output .= do_shortcode( $content );        
    $output .= '</div>';

    return $output; 
}
  • Have you found any solution for nesting same shortcodes? – Igor Jerosimić Sep 6 '15 at 8:41
4

There's a solution for that, actually. The shortcode you are using has the variable $content, whithout the filter do_shortcode, like this:

do_shortcode($content)

Open the file where there are the shortcodes and change $content for do_shortcode($content). It will work.

  • Thanks for your answer. Can you please explain it? There's already this in the shortcode parser: $output .= do_shortcode( $content ); What should I change in it? – jay Dec 4 '13 at 8:48
  • Could you post the full code of this shortcode? Btw, you will need to fix it in all shortcodes in order to be able to nest one to each other. – Gerard Dec 4 '13 at 18:22
  • I have added the code in my question, please check above. – jay Dec 5 '13 at 7:49
  • These shortcodes are ok. So the problem is in the use of them. For example this is working: [row][col size="6"]...[/col][/row]. I can see the first level works, but not others. I don't know any solution for it. – Gerard Dec 5 '13 at 12:00
1

I created a solution for my nested shortcodes, maybe you could use something from it.

I used a recursive regex (notice |(?R)), so it might be not that fast as the official do_shortcode, but it allows nesting shortcodes with the same name.

My request for it was to not have a fixed list of shortcodes (so all existing in the content shortcodes must be parsed), to allow any level of nesting, and also to use a structure of $atts, which contain some parameters, existing at the time of filling this exact content.

For $atts I wrote my own function, too, as I wanted $atts to include both everything coming from the content (and not only those, whose default value is defined), and the default values for those fields, existing in the default array and not coming from the shortcode values.

Here's my atts function:

function complete_atts_with_defaults( $pairs, $atts = array() ) {
  $out = $atts;
  foreach ($pairs as $name => $default) {
    if ( array_key_exists($name, $atts)  && !empty( $atts[$name] ) ) { continue; }
    //else
    $out[$name] = $default;
  }
  return $out;
}

And here's the other code:

define( 'OUR_SHORTCODE_FULL_REGEX', '@\[([a-z0-9_]+)([^\]]*)\]((?:[^[]|(?R))+)\[\/\1\]@' );
define( 'OUR_SHORTCODE_HALF_REGEX', '@\[([a-z0-9_]+)([^\]]*)\/\]@' );

function fill_all_post_placeholders( $text, $atts = array() ) {
  //...
  $text = str_replace( '%5B', '[', $text );
  $text = str_replace( '%5D', ']', $text );

  $atts = complete_atts_with_defaults(
        array(
            'value1' => 'Hi :)',
            'value2' => '',
            'value3' => '',
        ), $atts );

  //...

  $text = preg_replace_callback( OUR_SHORTCODE_HALF_REGEX, function( $match ) use ( $atts ) { return replace_half_shortcode_placeholder( $match[1], $match[2], $atts ); }, $text );
  $text = preg_replace_callback( OUR_SHORTCODE_FULL_REGEX, function( $match ) use ( $atts ) { return replace_shortcode_placeholder( $match[1], $match[2], $match[3], $atts ); }, $text );

  return $text;
}

function replace_shortcode_placeholder( $name, $params, $content, $atts ) {
  $content = preg_replace_callback( OUR_SHORTCODE_FULL_REGEX, function( $match ) use ( $atts ) { return replace_shortcode_placeholder( $match[1], $match[2], $match[3], $atts ); }, $content );
  //   $function_to_call = '_rp_' . $name;
  //   if ( function_exists( $function_to_call ) ) { return $function_to_call( $name, $params, $atts ); }
  //   //else
  //   $value = $atts[ $name ];
  //   if ( empty( $value ) ) { return ''; }
  //   //else
  //   return $value;

  return '<br>name: '  . $name . ' <br>params: ' . $params . ' <br>content: (' . $content . ')<br><br>';
}

function replace_half_shortcode_placeholder( $name, $params, $atts ) {
  //   $function_to_call = '_rp_' . $name;
  //   if ( function_exists( $function_to_call ) ) { return $function_to_call( $name, $params, $atts ); }
  //   //else
  //   $value = $atts[ $name ];
  //   if ( empty( $value ) ) { return ''; }
  //   //else
  //   return $value;

  return '<br>name half: '  . $name . ' <br>params half: ' . $params . '<br><br>';
}

I left for you the commented area intact, so that you could see how those functions could be used.

These "shortcodes" of mine are not registered, as you can see in the commented code, they work differently, dynamically.

Also, the necessary rule for these shortcodes to work would be, to always add '/' to the self-closing tags, like one would do in XML. (In the code they are called "half-shortcodes".)

Example to the content parsed by this code (sorry for the gibberish):

[show_text_if campaign="2899"]subscribing to this newsletter [show_text_if campaign="2901" field_value="'a href='http://ajshdash.com/asdhal/asdasdasd'" field_value2="айксчд асй даксчй д"]subscribing to this new newsletter[/show_text_if] [red value1="dfsdfs" value2="sdfkls dfh skjha skd"/][/show_text_if]

[color value3="askdfjajls" value4="lskdfhjsldhfs df"/]

[show_text_if_not campaign="2899"]asdklja slkd alkd alskdj alsjd alsj als jdalsk jals dalskj asjd <a href="http://example.com/experiment/" target="_blank">Experiment</a> once more hooray! [green value4="askljjlaskd"/] Я сегодня это Я и я! :)[/show_text_if_not]

[show_text_if field_name="campaign" field_value="2899"]slkjd alsjkd aljsd ajs d new[/show_text_if]

And I understand, that this code is not a direct solution to what you asked for, but maybe you could use some of it, to work out the solution yourself.

0

Your shortcode callback should appears something like:

add_shortcode('col', 'col_cb');

add_shortcode('row', 'row_cb');

function col_cb( $atts, $content ) {
  $content = do_shortcode($content);
  // ...
}

function row_cb( $atts, $content ) {
  $content = do_shortcode($content);
  // ...
}
  • Thanks for your answer. I'm already trying this, I have added the code in my question and I will appreciate if you can give any idea about it. – jay Dec 5 '13 at 7:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.