# Adresse-autocomplete i WooCommerce-checkout

> Installér pluginnet Lynbro Danadresse eller et lille mu-plugin til adresse-autocomplete i WooCommerce, og valider adressen, når ordren afgives.
>
> https://danadresse.dk/guides/woocommerce · verified 2026-11-02
WooCommerce har to checkouts: den klassiske (shortcoden `[woocommerce_checkout]`) og blok-checkout'en, som er standard i nye butikker. Begge består af almindelige input-felter, så adresse-widget'en kan kobles på. Her er de to veje: vores WordPress-plugin og et lille mu-plugin, du selv styrer.

## 1. Pluginnet: Lynbro Danadresse

Installér [Lynbro Danadresse](https://wordpress.org/plugins/lynbro-danadresse/) fra wordpress.org:

1. Gå til **Plugins → Tilføj nyt** i WordPress, søg efter "Lynbro Danadresse", klik **Installér** og **Aktivér**.
2. Opret en nøgle under [Nøgler](/dashboard/keys). Brug en almindelig *live*-nøgle **uden** tilladte domæner: pluginnet kalder API'et fra din egen server, og dér afvises en domænelåst nøgle, fordi et serverkald ikke har en `Origin`.
3. Sæt nøglen ind under **Lynbro → Danadresse → Settings**. Fanen **Status** laver et testopslag med nøglen.
4. Under **Integrations** er WooCommerce slået til fra start.

Det gør pluginnet i WooCommerce:

- Autocomplete i den klassiske checkout, blok-checkout'en og adresseformularerne under Min konto. Postnr. og by bliver udfyldt.
- Når en ordre med en dansk leveringsadresse afgives, tjekkes adressen mod registret (datavask). Resultatet (præcis, tæt på eller ikke genkendt) gemmes på ordren og vises for butikkens administrator. Du kan vælge at stoppe ordrer med tydeligt ugyldige adresser. Kan API'et ikke nås, blokeres checkout'en aldrig.
- **Statistics** viser sitets opslag pr. dag, og **Log** forklarer de seneste fejl i almindelige ord.

Vil du hellere have din egen kode, eller skal browseren kalde API'et direkte med en domænelåst nøgle, så brug mu-pluginnet nedenfor.

## 2. Opret en browsernøgle til mu-pluginnet

Mu-pluginnet kalder API'et direkte fra browseren. Opret en *live*-nøgle under [Nøgler](/dashboard/keys) og lås den til `minbutik.dk` og `www.minbutik.dk` under **Tilladte domæner**. Se [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener).

## 3. Læg mu-pluginnet ind

Gem filen som `wp-content/mu-plugins/danadresse.php`. WordPress indlæser filer i `mu-plugins` automatisk.

```php id=mu-plugin run=syntax
<?php
/**
 * Plugin Name: Danadresse autocomplete (WooCommerce)
 */
if (!defined('ABSPATH')) {
    exit;
}

add_action('wp_enqueue_scripts', function () {
    if (!function_exists('is_checkout') || !(is_checkout() || is_account_page())) {
        return;
    }
    wp_enqueue_script(
        'danadresse-autocomplete',
        'https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js',
        [],
        null,
        true
    );
    wp_add_inline_script('danadresse-autocomplete', <<<'JS'
const API_KEY = "DIN_BROWSER_NØGLE";

function setField(el, value, events) {
  if (!el || value == null) return;
  const setter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value").set;
  setter.call(el, value);
  for (const type of events || ["input", "change"]) {
    el.dispatchEvent(new Event(type, { bubbles: true }));
  }
}

function streetLine(a) {
  let line = a.vejnavn + " " + a.husnr;
  if (a.etage) line += ", " + a.etage + ".";
  if (a["dør"]) line += " " + a["dør"];
  return line;
}

// Klassisk: billing_address_1 → billing_postcode. Blok: billing-address_1 → billing-postcode.
function bind(input) {
  DanadresseAutocomplete.attach(input, {
    apiKey: API_KEY,
    onSelect(a) {
      setField(input, streetLine(a), ["change"]);
      setField(document.getElementById(input.id.replace("address_1", "postcode")), a.postnr);
      setField(document.getElementById(input.id.replace("address_1", "city")), a.postnrnavn);
    },
  });
}

function bindAll() {
  document
    .querySelectorAll("#billing_address_1, #shipping_address_1, #billing-address_1, #shipping-address_1")
    .forEach(bind);
}
bindAll();
// Blok-checkout'en tegner felterne senere og igen, når kunden skifter adresse.
new MutationObserver(bindAll).observe(document.body, { childList: true, subtree: true });
JS
    );
});
```

Widget'en kobler sig kun på et felt én gang, så det er ufarligt, at `bindAll` kører ved hver ændring i siden.

## 4. Test begge checkouts

Skriv en adresse, vælg et forslag, og gennemfør en testordre. Tjek i ordren, at vej, postnr. og by er gemt. Blok-checkout'en er bygget i React. Koden sender `input`- og `change`-events, så React opdager værdien, men tjek det på din WooCommerce-version, før du går live. Felternes id'er kan du se med **Inspicér**.

## 5. Valgfrit: valider ved bestilling

Med en server-nøgle uden domænelås kan du tjekke adressen, før ordren oprettes. Koden sender vej, husnr. og postnr. til `/datavask/adgangsadresser`, som tjekker bygningen. Etage og dør bliver ikke tjekket. Hooket kører kun i den klassiske checkout. Nøglen læses fra miljøvariablen `DANADRESSE_API_KEY`.

```php id=checkout-datavask run=syntax
<?php
add_action('woocommerce_after_checkout_validation', function (array $data, WP_Error $errors) {
    $prefix = !empty($data['ship_to_different_address']) ? 'shipping_' : 'billing_';
    if (($data[$prefix . 'country'] ?? '') !== 'DK') {
        return;
    }
    // Kun vej og husnr. (før første komma) + postnr.
    $street = trim(strtok((string) ($data[$prefix . 'address_1'] ?? ''), ','));
    $betegnelse = $street . ', ' . ($data[$prefix . 'postcode'] ?? '');
    $res = wp_remote_get(
        'https://api.danadresse.dk/datavask/adgangsadresser?' . http_build_query(['betegnelse' => $betegnelse]),
        ['headers' => ['X-Api-Key' => getenv('DANADRESSE_API_KEY')], 'timeout' => 5]
    );
    if (is_wp_error($res) || wp_remote_retrieve_response_code($res) !== 200) {
        return; // API'et svarer ikke: lad ordren gå igennem
    }
    $vask = json_decode(wp_remote_retrieve_body($res), true);
    if (($vask['kategori'] ?? '') === 'C') {
        $errors->add('validation', 'Vi kunne ikke finde adressen. Tjek vej, husnummer og postnummer.');
    }
}, 10, 2);
```

Kategori A og B accepteres, C stopper ordren. Læs mere i [Datavask i checkout](/guides/datavask-i-checkout).

## Næste skridt

- [WooCommerce-siden](/woocommerce-adresse) og [checkout-oversigten](/checkout-adresse)
- [Elementor-formularer](/guides/elementor) på samme WordPress-site
- Pluginnet på wordpress.org: [Lynbro Danadresse](https://wordpress.org/plugins/lynbro-danadresse/)
