ACF link field values lost after database migration
Migrating a WordPress database from production to local — or between servers — is routine. But ACF Link fields store absolute URLs in a serialized format, which means a plain search-and-replace in phpMyAdmin will corrupt the data. Here’s how to handle it properly.
Problem: When using ACF, some field values — such as Link fields — are lost after importing a database.
Solution: Interestingly, if you use relative links, everything works fine — but that's rarely practical. A much better approach is to use the Search & Replace for WordPress Databases utility. After downloading it, place the folder in the root of your site and rename it to something like replace for convenience. Then open http://yourdomain/replace in a browser, fill in both site URLs, and click "Live Run". For cleaner output, you can also use this helper function:
function the_custom_acf_link( $acf_link_field, $class ) {
if ( ! $acf_link_field ) {
return;
}
$link_url = esc_url( $acf_link_field['url'] );
$link_class = $class ? ' class="' . sanitize_html_class( $class ) . '" ' : '';
$link_target = $acf_link_field['target'] ? $acf_link_field['target'] : '_self';
$link_title = esc_html( $acf_link_field['title'] );
$link = '<a href="' . $link_url . '"' . $link_class . 'target="' . esc_attr( $link_target ) . '">' . $link_title . '</a>';
echo $link;
}
Alternative approach: Sometimes it's preferable to use two separate ACF text fields for the URL and the title, plus a true/false field for the target (e.g. "Open in new tab"). You can then write a helper function to output them:
function the_custom_acf_link( $title, $url, $target, $class = '' ) {
if ( ! $url ) {
return;
}
$target = $target ? '_blank' : '_self';
$class = $class ? ' class="' . esc_attr( $class ) . '" ' : ' ';
$link = '<a href="' . esc_url( $url ) . '"' . $class . 'target="' . $target . '">' . esc_html( $title ) . '</a>';
echo $link;
}
NOTE: The Search & Replace script handles serialized data correctly — a key advantage over a plain SQL REPLACE(), which breaks serialized arrays by leaving the stored byte-count wrong. Always run it against a database backup first and verify the results before touching production.
Sources: