Jeg lovede mig selv.

Nok taget flere uger at skrive, men udgivet den 6. november 2023

Jeg er lidt af en perfektionist. Det plejer jeg i hvert fald at tænke om mig selv. Nu jeg er blevet ældre, og klogere, ved jeg efterhånden, at jeg tit bare trækker tiden ud. Som de over fem minutter jeg lige har brugt på at gennemskue hvorfor vi ikke har ordet “procrastinate” på dansk.

Så da jeg skulle bruge et telefonsystem til et af mine egne projekter, lovede jeg mig selv at finde et fint system på abonnement. For de findes, koster ikke alverden og findes endda på dansk.

Så glad skrev jeg mig op, og begyndte at sætte telefonsystemet op som jeg ønskede. Lige så langsomt begyndte perfektionisten dog at komme op i mig. Jeg forsøgte at holde ham tilbage. Fortalte at det ikke gør så meget, at velkomstbeskeden bliver indtalt med en stemme, men at stemmen der fortæller hvor man er i køen er med en anden stemme. Det er nok bare mig der synes det er fjollet, at mine kunder skal lytte til flere forskellige stemmer når de ringer ind.

Men man kunne kun have en telefonsvarebesked. “Hvorfor?”, tænkte perfektionisten i mig, hvilket hurtigt blev efterfuldt af et “JA, hvorfor?!” af brokrøven i mig. Så nu var det to mod en, men jeg holdte fast. Jeg var dog enig i, at det ville være rart at kunne have forskellige beskeder om der bliver ringet i åbningstiden eller uden for åbningstiden. Det var dog stadig så meget nemmere at sætte et telefonsystem op, end at kode et fra bunden.

Da det gik op for mig, at telefonsystemet ikke kunne gennemskue om mine kunder ringede fra ukendt nummer stoppede legen dog. Brokrøven tog totalt over; “Hvor dum skal man være for at bygge et system hvor man tilbyder kunder der ringer ind, at hvis de blot trykker 1, så ringer man tilbage og så ikke tage hensyn til at de måske har ukendt nummer!?”

Jeg var enig. Ikke særligt brugbart at få besked fra ens telefonsystem om at en kunde gerne vil ringes op, men vi har ikke hans nummer.

Suk! Så måtte jeg jo bygge det selv. Hvilket faktisk viste sig ikke at være så stor en mundfuld som man kunne frygte.

1) Først finder man en service som https://www.twilio.com, hvor man kan købe et danske telefonnummer. Hos Twilio kunne man endda købe hvad jeg har hørt omtalt som et “Guldnummer” til normal pris.

2) Så tjekker man deres dokumentation ud. Jeg besluttede at bygge mit telefonsystem ind i mit website som er WordPress. Fordi så skulle jeg ikke til at spinde et nyt system op og jeg er virkelig god til WordPress. Så min dokumentation er for PHP, https://www.twilio.com/docs/voice/quickstart/php, og jeg hentede deres PHP SDK.

3) Så er det bare at gå i gang med at bygge. WordPress har med tiden fået en rigtig fin måde at bygge et REST API, https://developer.wordpress.org/rest-api/, så det kastede jeg mig over. Det handler nemlig om at have forskellige endpoints som Twilio kan kalde alt efter hvad man beder systemet om.

Efter to dage er Bob din onkel.

Her er lidt kode at kigge på for at vise at det ikke er så komplekst. Dette er ikke en brugbar gennemgang for en begynder til at bygge et telefonsystem. Det er blot en smagsprøve af hvordan man kan bygge det (nemt) i WordPress.


/* Initial call */
register_rest_route( $this->endpoint, '/call/incoming', [
	'methods' => 'POST',
	'callback' => [ new TwilioController, 'incoming' ],
	'permission_callback' => [ $this, 'authenticateTwilio' ]
] );

Dette viser hvordan, og hvor simpelt, man kan sætte endpoints op i WordPress. Noget der kan drille, er at WordPress som standard returnerer JSON, mens Twilio har brug for at der bliver returneret XML. Jeg har løst det ved at hacke mig ind i følgende filter developer.wordpress.org/reference/hooks/rest_pre_serve_request/.


public function incoming ( $request ) {
  $call = $request->get_params();

  if ( $this->are_we_open() == true ) {
    return $this->we_are_open( $call );
  }

  return $this->we_are_closed( $call );
}

Når et kald kommer ind tjekker jeg om det er i åbningstiden, så jeg kan give forskellige beskeder, og forløb, til vedkommende som ringer ind.


private function we_are_open ( $call ) {

  if ( $this->known_caller( $call ) == true ) {
    $action = site_url( '/wp-json/' . ENDPOINT . '/call/open_unavailable_known_number' );
  } else {
    $action = site_url( '/wp-json/' . ENDPOINT . '/call/open_unavailable_unknown_number' );
  }

  $response = new VoiceResponse();
  $response->say('Velkommen. Vent venligst mens jeg sætter dig i forbindelse med et menneske.', ['language' => 'da-DK']);
  $response->dial('+45XXXXXXXX', [
    'action' => $action,
    'callerId' => '+45XXXXXXXX',
    'timeout' => 5,
  ] );

  return $response;
}

Jeg har en funktion til at gennemskue om vi har et nummer vi kan ringe tilbage på. Ingen grund til at tilbyde at vi kan ringe tilbage hvis vi ikke kender deres nummer.


private function we_are_closed ( $call ) {
  $response = new VoiceResponse();

  $response->gather([
      'action' => site_url( '/wp-json/' . ENDPOINT . '/call/gather' ),
      'numDigits' => 1,
      'timeout' => 15
  ])->say('Du har ringet uden for vores normale åbningstid. Tryk 1 hvis det er virkelig vigtigt. Tryk 2 hvis du ønsker at ligge en besked til os. Tak for tålmodigheden. Denne besked vil blive gentaget om lidt.', ['language' => 'da-DK']);
  $response->redirect( site_url( '/wp-json/' . ENDPOINT . '/call/incoming' ) );

  return $response;
}

Sidste kodeblok viser, at det er relativt simpelt at sætte en trykmenu op. Hedder det mon en trykmenu? Ikke vigtigt, men jeg håber at dette lidt viser, at det ikke er totalt raketvidenskab at bygge sit eget telefonsystem.

Nu mangler jeg blot at få indtalt beskederne. For selvom Twilio faktisk kan læse op på dansk, som man kan se i koden, så lyder det på ingen måde godt.

Lad os se hvor lang tid jeg kan trække indtalingen ud. Skriv gerne til mig hvis I ønsker hjælp til at bygge jeres eget telefonsystem. Så har jeg i det mindste en nogenlunde god undskyldning for det.

Tak for din tid.