ACF link field values are lost after database migration

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:

  1. https://www.advancedcustomfields.com/resources/link/
  2. https://support.advancedcustomfields.com/forums/topic/link-field-values-are-lost-after-database-migration/
  3. https://interconnectit.com/products/search-and-replace-for-wordpress-databases/