skip to Main Content

I have a PHP function that generates vCard data from the WordPress ACF plugin. The German text is not displaying correctly in Outlook’s desktop version, but it works fine on the mobile version. Here’s the code I’m using to generate the vCard:

    function generate_vcard($post_id) {
    // Get ACF field values for the post
    $title = utf8_encode(get_field('title', $post_id));
    $first_name = utf8_encode(get_field('first_name', $post_id));
    $last_name = utf8_encode(get_field('last_name', $post_id));
    $position = utf8_encode(get_field('position', $post_id));
    $company = utf8_encode(get_field('company', $post_id));
    $birthday = utf8_encode(get_field('birthday', $post_id));
    $office_phone = utf8_encode(get_field('office_phone', $post_id));
    $cell_phone = utf8_encode(get_field('cell_phone', $post_id));
    $email_1 = utf8_encode(get_field('email_1', $post_id));
    $email_2 = utf8_encode(get_field('email_2', $post_id));
    $website = utf8_encode(get_field('website', $post_id));

    // Get profile image URL from ACF field
    $profile_image = get_field('profile_image', $post_id);

    // Encode the image to base64
    $image_data = file_get_contents($profile_image);
    $base64_image = base64_encode($image_data);

    // Generate vCard content
    $vcard = "BEGIN:VCARDrn";
    $vcard .= "VERSION:3.0rn";
    $vcard .= "PHOTO;TYPE=JPEG;ENCODING=b;VALUE=URL:$base64_imagern";
    $vcard .= "FN:$first_name $last_namern";
    $vcard .= "N:$last_name;$first_name;;;rn";
    $vcard .= "ORG;CHARSET=windows-1252:$companyrn";
    $vcard .= "TITLE:$positionrn";
    $vcard .= "BDAY:$birthdayrn";
    $vcard .= "TEL;TYPE=WORK,VOICE:$office_phonern";
    $vcard .= "TEL;TYPE=CELL,VOICE:$cell_phonern";
    $vcard .= "EMAIL:$email_1rn";
    $vcard .= "EMAIL:$email_2rn";
    $vcard .= "URL:$websitern";
    $vcard .= "END:VCARDrn";

    // Set headers to trigger download with Windows-1252 encoding
    header("Content-Type: text/vcard; charset=windows-1252");
    header("Content-Disposition: attachment; filename=contact.vcf; charset=windows-1252");

    // Output vCard content with Windows-1252 encoding
    echo $vcard;
    exit;
}

add_action('wp', 'export_vcard');
function export_vcard() {
    if (isset($_GET['export_vcard']) && $_GET['export_vcard'] == 1) {
        $post_id = get_the_ID();
        generate_vcard($post_id);
    }
}

I meant that the German text in the vCard is not rendering as expected in Outlook’s desktop version. the German text appears für but the actual text is für.

enter image description here

I have tried changing the encoding of the vCard file to UTF-8, but that did not fix the problem.
Does anyone know why this is happening and how to fix it?

2

Answers


  1. function get_utf8_field($field, $post_id) {
        $value = get_field($field, $post_id);
        return $value ? mb_convert_encoding($value, 'UTF-8', 'auto') : '';
    }
    
    function generate_vcard($post_id) {
        // Get ACF field values for the post
        $fields = ['title', 'first_name', 'last_name', 'position', 'company', 'birthday', 'office_phone', 'cell_phone', 'email_1', 'email_2', 'website'];
        $data = array_map(function($field) use ($post_id) {
            return get_utf8_field($field, $post_id);
        }, array_combine($fields, $fields));
    
        // Get profile image URL from ACF field
        $profile_image = get_field('profile_image', $post_id);
    
        // Encode the image to base64
        $image_data = @file_get_contents($profile_image);
        if ($image_data === false) {
            // Handle error...
        }
        $base64_image = base64_encode($image_data);
    
        // Generate vCard content
        $vcard = "xEFxBBxBF"; // UTF-8 BOM
        $vcard .= "BEGIN:VCARDrn";
        $vcard .= "VERSION:3.0rn";
        if (!empty($base64_image)) {
            $vcard .= "PHOTO;TYPE=JPEG;ENCODING=b;VALUE=URL:$base64_imagern";
        }
        if (!empty($data['first_name']) && !empty($data['last_name'])) {
            $vcard .= "FN:{$data['first_name']} {$data['last_name']}rn";
            $vcard .= "N:{$data['last_name']};{$data['first_name']};;;rn";
        }
        if (!empty($data['company'])) {
            $vcard .= "ORG:{$data['company']}rn";
        }
        if (!empty($data['position'])) {
            $vcard .= "TITLE:{$data['position']}rn";
        }
        if (!empty($data['birthday'])) {
            $vcard .= "BDAY:{$data['birthday']}rn";
        }
        if (!empty($data['office_phone'])) {
            $vcard .= "TEL;TYPE=WORK,VOICE:{$data['office_phone']}rn";
        }
        if (!empty($data['cell_phone'])) {
            $vcard .= "TEL;TYPE=CELL,VOICE:{$data['cell_phone']}rn";
        }
        if (!empty($data['email_1'])) {
            $vcard .= "EMAIL:{$data['email_1']}rn";
        }
        if (!empty($data['email_2'])) {
            $vcard .= "EMAIL:{$data['email_2']}rn";
        }
        if (!empty($data['website'])) {
            $vcard .= "URL:{$data['website']}rn";
        }
    
        $vcard .= "END:VCARDrn";
    
        // Set headers to trigger download with UTF-8 encoding
        header("Content-Type: text/vcard; charset=UTF-8");
        header("Content-Disposition: attachment; filename=contact.vcf");
    
        // Output vCard content with UTF-8 encoding
        echo utf8_encode($vcard);
    }
    
    add_action('wp', 'export_vcard');
    function export_vcard() {
      if (isset($_GET['export_vcard']) && $_GET['export_vcard'] == 1) {
          generate_vcard(get_the_ID());
      }
    }
    

    Here are the changes I made:

    1. Consistent Encoding: I replaced utf8_encode with mb_convert_encoding in the get_utf8_field function. This function is more flexible and can handle different types of encodings. I also set the charset in the headers to UTF-8.

    2. UTF-8 BOM: I added the UTF-8 Byte Order Mark (BOM) at the beginning of your vCard content.

    3. Quoted-printable Encoding: I didn’t apply this fix because it’s not necessary when using UTF-8 encoding. If you still encounter issues, you might want to consider applying this fix.

    Login or Signup to reply.
  2. WordPress is using utf8mb4 by default, so you must not use utf8_encode on get_field as this will result in double-encoding. Stay with utf-8 (it’s the recommended default for vCard 3.0 and a must for vCard 4.0) when creating the vCard and setting the headers. Do not add a BOM. Use utf-8 in all lower case, as some versions of Outlook do not accept in all upper case.

    Create a minimum reproducible example an then go from there. I’ve tested with:

    <?php
    
    // Sample data
    $first_name = 'Björn';
    $last_name = 'Ängstler';
    $company = 'Arzt für innere Medizin';
    
    // Create vCard
    $vcard = "BEGIN:VCARDrn";
    $vcard .= "VERSION:3.0rn";
    $vcard .= "FN;CHARSET=utf-8:$first_name $last_namern";
    $vcard .= "N;CHARSET=utf-8:$last_name;$first_name;;;rn";
    $vcard .= "ORG;CHARSET=utf-8:$companyrn";
    $vcard .= "END:VCARDrn";
    
    // Set headers to trigger download
    header("Content-Type: text/vcard; charset=utf-8");
    header("Content-Disposition: attachment; filename=contact.vcf; charset=utf-8");
    
    // Output vCard content
    die($vcard);
    

    and this imports just fine. If you still encounter problems thereafter, export a vCard from the client in question (e.g. Outlook) and open both the export and your vCard in a text editor to compare them.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search