0

I'd like to wrap existing shortcodes in post content inside a new shortcode that I'm adding to my plugin. The existing content looks like this:

 Some text - could be <span>HTML</span> or other shortcodes
 ....
 [component id=12]
 [component id=13]
 [component id=14]
 ....
 Some text - could be <span>HTML</span> or another shortcodes

I'm trying to write a script that will go post by post, extract out any shortcodes of the form [component id=X] and wrap them in another shortcode as follows:

 Some text - could be <span>HTML</span> or other shortcodes
 ....
 [components]
     [component id=12]
     [component id=13]
     [component id=14]
 [/components]
 ....
 Some text - could be <span>HTML</span> or another shortcodes

I'm having trouble writing up the regex for this. I'm hoping to use preg_replace_callback() to achieve this, but not sure if this is the appropriate function or not.

4
  • This is very close to what you are looking for.
    – s_ha_dum
    Commented May 7, 2014 at 22:59
  • Have you already searched the site?
    – kaiser
    Commented May 7, 2014 at 23:07
  • Yep. Most of the cases on the site give examples on how to find specific instances of shortcodes, but I couldn't find a case that wraps shortcodes inside a newly defined shortcode. Commented May 7, 2014 at 23:14
  • 1
    The code in the link I posted should get you about 90% of the way there. Take a good look at it.
    – s_ha_dum
    Commented May 8, 2014 at 0:00

1 Answer 1

0

Here is the script I came up with. It loops through all the posts in a WordPress instance and splits it up into three sections:

  1. The HTML/content before the row of shortcodes
  2. The row of shortcodes
  3. The HTML/content after the row of shortcodes

I decided to use substr() to split up the content. I then re-assemble everything together towards the end and include the "wrapping" shortcode around the middle piece.

$args = array( 'numberposts' => -1, 'post_status' => 'publish|draft|trash' )
$posts = get_posts( $args );
if( !empty( $posts ) ){
    foreach( $posts as $post ){
        $content = $post->post_content;
        if( !has_shortcode( $content, 'components') ){
            $pattern = '/\[component id=\"[0-9]+\"\]/';
            preg_match_all( $pattern, $content, $matches, PREG_OFFSET_CAPTURE);

            $first_match = $matches[0][0];
            $first_match_start = $first_match[1]; // Start position of the first match

            $last_match = $matches[0][ count($matches[0]) - 1 ];
            $last_match_start = $last_match[1];
            $last_match_end = $last_match_start + strlen($last_match[0]);

            $before_html = substr($content, 0, $first_match_start); // Get all the content before the first match of [component id="XYZ"]
            $component_shortcodes = substr($content, $first_match_start, $last_match_end - $first_match_start ); // Get everything in between the first [component id="XYZ"] and the last
            $after_html = substr($content, $last_match_end ); // Get everything after the last [component id="XYZ"] match
            // Perform the actual wrapping here
            $new_content = $before_html . '[components]' . $component_shortcodes . '[/components]' . $after_html;
            $post->post_content = $new_content;
            wp_update_post( $post );
        }
    }
}

Your Answer

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

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