Last year I migrated a mass amount of news content dating back to 2013 from a client site in WordPress. The theme it was on was very outdated and no longer getting updates, and it was using several page builders at once. I was using WP All Export and WP All Import, and I was expecting the usual broken sliders, embedded video missing, a few strings of symbols and then something new always happens, too.
What I wasn’t expecting is not finding a free PHP shortcode stripper I could just use to make it a little easier, at least not at the time I was working. There is a PHP field to use for code to do this, I just couldn’t find anything pre-written that worked for what I was doing. There are plugins that clean builder shortcodes from the database after import, but it’s already in the database at that point, and I thought it would be easier to work with the data when I exported it from the original website and still had it as a reference.
This became one of my first experiments using AI to code. (Later experiment here, and now I do this all the time.) I built a PHP snippet that runs inside WP All Export and WP All Import’s built-in PHP field — originally written with ChatGPT in August of 2025 (with a lot of frustration and yelling because it didn’t work at all like I wanted it to the first billion times; it was a different time for AI coding than it is now in 2026), then cleaned it up and code-checked it in Claude recently. I also rewrote it to look at the general problem and be theme and builder agnostic as much as possible rather than the specific to the client site I was working on then. I’ve done WordPress theme migrations sooooo many times and always run into the same issues.
I’m posting both files here as a free tool. If nothing else, you can use them as a starting point on your own or with your own AI code assistant to adapt to your own needs.
What the PHP tool does
The cleaner strips page builder shortcodes from Avada/Fusion, WPBakery/Visual Composer, Divi, Swift Builder, Beaver Builder, SiteOrigin, Themify, Cornerstone, MK/Jupiter, Enfold, Salient, and X Theme. It also strips Elementor HTML — Elementor doesn’t use shortcodes, it embeds rendered HTML with data-* attributes directly in post_content.
Beyond stripping, it converts sliders to stacked HTML so content isn’t silently deleted and just missing, only to get a request about it months later when the original site is gone. (Hello Wayback Machine for that!) It recovers video embed URLs from builder shortcodes and outputs them as plain URLs, which WordPress auto-embeds natively. Anywhere it can’t recover content in some readable way, it drops a searchable HTML comment instead of just skipping it. Native WordPress shortcodes are left alone as they will still work in the new WordPress site.
Two PHP files, one for WP Import and WP Export
bcc-export.php runs on your old site. While your old database is still intact, WordPress can resolve attachment IDs to real image URLs using wp_get_attachment_url(). Swift Builder and WPBakery both store slider and gallery images as integer IDs — image=”423″, for example. Once you’ve left that database, those IDs are meaningless. The export version converts every one of them to a real URL before the file leaves the old site.
bcc-import.php runs on the new site. WP All Import has a Preview feature that shows exactly what the cleaner will produce before anything touches your database — which is the main reason the import version exists. Use it. It also works as a standalone cleaner if you don’t have access to the old site anymore. It just can’t resolve attachment IDs and will leave a BCC-SKIP comment wherever it hits one.
Run both when you can: export version on the old site first, then import the cleaned file with the import version on the new site. The preview is your final check before anything commits.
The attachment ID issue
When you upload an image in WordPress, it gets stored in the database as a post with an auto-incremented ID. Page builders like Swift Builder and WPBakery reference that image in their shortcodes as an integer: image=”423″ or images=”12,34,56″.
When you export posts and import them into a new WordPress install, that ID has no meaning. The new database has its own IDs. ID 423 might be a completely different image — or might not exist at all.
The export version solves this by calling wp_get_attachment_url(423) while the old database is still live, converting the ID to a full URL like https://yoursite.com/wp-content/uploads/2023/04/hero-image.jpg. That URL comes over in the migration.
Setup
Export side: In WP All Export, create a new export for your post type. For the post_content field in your field mapping, click the PHP icon and enter:
return bcc_clean( $post_content );
Then paste the full bcc-export.php contents into the Export PHP Functions editor. Alternatively, save the file to wp-content/uploads/wpallexport/functions.php — functions there only run during export processing and won’t affect your live site.
Import side: In WP All Import, create a new import with your export file. Same one-liner in the post_content PHP field:
return bcc_clean( $post_content );
Paste the full bcc-import.php contents into the Import PHP Functions editor, then use the Preview button before running the full import. Both files define the same function names — never load both at the same time.
Finding what needs manual work
Anywhere the cleaner can’t recover content, it leaves an HTML comment in place of the missing content. The comment starts with BCC-SKIP, followed by the shortcode that triggered it and a brief note explaining why it couldn’t be resolved — usually because it hit an attachment ID that only the old database can access. After your import, search all post content for BCC-SKIP to find every post that needs a manual look. The free Search Regex plugin can do this across all posts at once from the WordPress admin.
What can’t be recovered — regardless of how the PHP is written
- Fusion/Avada sliders store all slide data in a separate fusion_slider custom post type, not in post_content. The [(don’t read this as a shortcode) fusion_slider] shortcode in your content is just a reference ID. Export and import that CPT separately.
- Revolution Slider, Smart Slider 3, and LayerSlider all store slide data in their own database tables.
- Elementor dynamic widgets — posts grids, portfolio carousels — render from other database tables at page load. Their stored HTML in post_content is empty scaffolding.
- Some Elementor setups also store layout JSON in a _elementor_data post meta field rather than post_content. If Elementor pages come through nearly empty after cleaning, that’s why. You’d need to export that meta field separately.
Slider output format
Slider content comes out as stacked HTML: a div with class bcc-slide, containing an img with the resolved URL, an h2 with the slide title, and a p with body copy. Slides missing a title or body copy just omit those elements.
bcc-slide has no built-in styles. Add CSS to your new theme to display them however you want, or use Search Regex after import to bulk-replace them with your new site’s slider shortcode format.
Adding builders or keeping plugin shortcodes
To add a builder not in the list, find the $prefixes array in bcc_strip_builder_shortcodes() and add a line with the shortcode prefix and a label. Any shortcode starting with that prefix will be handled from there.
To keep plugin shortcodes intact — WooCommerce, contact forms, anything like that — comment out the bcc_strip_remaining_shortcodes() call in bcc_clean(). The prefix-based stripper only touches known builder prefixes and won’t touch plugin shortcodes on its own.
The code
Both files are posted below with inline comments throughout. Every section explains what it’s doing and why. The Swift Builder and Elementor sections go into more detail on how those builders store content — it’s my experience they’re the worst offenders (the cause of much yelling in my office, again), and understanding the structure is what makes the cleaning logic make sense.
