i’m trying to wrap each shortcode in div with special data attributes, but when i’m using nested shortcode they don’t wrapped, where i’m wrong? thanks

public function wrapShortcode( $content )
{
    preg_match_all( "https://wordpress.stackexchange.com/" . get_shortcode_regex() . "https://wordpress.stackexchange.com/", trim( $content ), $found , PREG_SET_ORDER | PREG_OFFSET_CAPTURE );

    if ( ! empty( $found  ) ) {
        for ( $i = count( $found  ) - 1; $i >= 0; $i-- ) {
            $id = md5( time() . '-' . $this->tag_index ++ );
            $match = $found[ $i ];

            $scCont = substr( $content, $match[0][1], strlen( $match[0][0] ) );
            $shortcode = array(
                'tag'   => $match[2][0]
            );

            $modifiedShortcode="<div class="shortcode" data-name="".$shortcode['tag'].'">'.$scCont.'</div>';
            $content = substr( $content, 0, $match[0][1] ) . $modifiedShortcode . substr( $content, $match[0][1] + strlen( $match[0][0] ) );
        }
    }

    remove_action( 'the_content', array( $this, 'wrapShortcode' ), 1 );

    // Stray spaces can create lost paragraph tags.
    $content = preg_replace( '/(\/\w+>)\s+(<\/\w+)/', '$1$2', $content );
    return apply_filters( 'bq_wrapShortcode', $content );
}
add_filter( 'the_content', array( $this, 'wrapShortcode' ), -9999999 );

this code works fine with shortcodes like this:

[shortcode][/shortcode]

and return:

<div class="shortcode" data-name="shortcode">[shortcode][/shortcode]</div>

but when i used nested shortcode my code wrap only first shortcode, inner shortcode not wraped:

<div class="shortcode" data-name="shortcode">[shortcode][inner_shortcode][/inner_shortcode][/shortcode]</div>

but must return this:

<div class="shortcode" data-name="shortcode">
     [shortcode]
     <div class="shortcode" data-name="inner_shortcode">
        [inner_shortcode][/inner_shortcode]                 
     </div>
     [/shortcode]
</div>

where i’m wrong? thanks!

1 Answer
1

You need to recurse into the shortcode content ($m[5] as returned by get_shortcode_regex()), the standard way being to use preg_replace_callback():

    public function wrapShortcode( $content )
    {
        $content = preg_replace_callback( "https://wordpress.stackexchange.com/" . get_shortcode_regex() . '/s', array( $this, 'wrapShortcodeCallback' ), $content );

        remove_filter( 'the_content', array( $this, 'wrapShortcode' ), -9999999 );

        // Stray spaces can create lost paragraph tags.
        $content = preg_replace( '/(\/\w+>)\s+(<\/\w+)/', '$1$2', $content );
        return apply_filters( 'bq_wrapShortcode', $content );
    }
    public function wrapShortcodeCallback( $m )
    {
        $id = md5( time() . '-' . $this->tag_index ++ );
        if ( $m[5] !== '' ) {
            // Recurse into content.
            $m[5] = preg_replace_callback( "https://wordpress.stackexchange.com/" . get_shortcode_regex() . '/s', array( $this, 'wrapShortcodeCallback' ), $m[5] );
            $scCont="[" . $m[1] . $m[2] . $m[3] . ']' . $m[5] . '[/' . $m[2] . ']' . $m[6];
        } else {
            $scCont="[" . $m[1] . $m[2] . $m[3] . $m[4] . ']' . $m[6];
        }
        return '<div class="shortcode" data-name="'.$m[2].'">'.$scCont.'</div>';
    }

Leave a Reply

Your email address will not be published. Required fields are marked *