Kapcsolat űrlap és levél módosítása a Drupalban

Hojtsy Gábor képe

Korábban már írtam a hook_form_alter() előnyeiről és működéséről. Ennek segítségével – némi programozással – elérhetjük, hogy a Drupal módosítása nélkül a rendszer űrlapjai kedvünkre változzanak meg. De mi van akkor, ha az űrlapok változtatása nem elegendő? Az utóbbi hetekben a Weblabor.hu 4.6.x-es rendszerről 5.x-es Drupal rendszerre frissítésén is munkálkodom szabadidőmben, és éppen ma értem el a Weblabor szerkesztőit is megcímző kapcsolati űrlap funkcióhoz. Lássuk mi az igényelt funkció, és milyen kényelmes megtenni a módosításainkat Drupal 5.1-gyel!

A kérdéses szolgáltatás csak az adminisztrátorok számára érhető el a Weblaboron, és azt teszi lehetővé, hogy amikor egy levelet küldünk (jellemzően valamilyen moderációs lépésről) egy felhasználó kapcsolat űrlapjáról az adott tagnak, akkor azt egyben cc-zzük is a Weblabor szerkesztőinek. Fontos, hogy egy cc fejléc elemet veszünk fel a levélbe, és a Drupal beépített 'másolatot kérek' funkciójával ellentétben nem új levelet küldünk. A cc fejléc használata ugyanis lehetővé teszi, hogy a szerkesztők is azonnal reagáljanak, hozzátegyék saját véleményünket a levélhez úgy, hogy azt a szerkesztők és a felhasználónk is megkapja. Ráadásul szálkövető marad a levelezés.

A fejlesztői alapproblémám egy a korábbi Drupal 4.6-os rendszerkód módosításával megvalósított szolgáltatás átültetése ezúttal már oly módon, hogy ne kelljen Drupal kódot módosítanom. Szerencsére a két ehhez szükséges eszköz a Drupal 5.0-val megérkezett, tudok megjelenített űrlapot és elküldött levelet is módosítani. A demonstráció kedvéért nevezzük a modulunkat wlcontact-nak, a domain pedig legyen example.com (így aki innen másolja a kódot, az nem rögtön nekünk címzi a leveleit).

Először is az űrlapot kell megváltoztatnom. Itt azonosítani kell, hogy a felhasználói kapcsolat űrlapról van szó, és adminisztrátorral van dolgunk. Ha ez teljesül, akkor felveszünk egy új 'toeditors' elemet az űrlapba, ami jelölőnégyzet típusú. Magyarázatot is adunk, hiszen a működés eltérő a beépített másolat funkciótól (és az összekeverés elkerülése érdekében arra a beépített elemre is adunk magyarázatot). Meg kell még oldanunk, hogy az új elemünk a submit gomb fölött jelenjen meg. Mivel ebben az űrlapban nincsenek megadott súlyozások, a submit gombnak nagyobb súlyt adunk meg, mint a saját jelölőnégyzetünknek. Ezzel kész is az űrlap külalakja. Még egy dologra kell figyelnünk, mégpedig, hogy értesüljünk az űrlap elküldéséről és feldolgozzuk a másolat kérést. Ennek érdekében az űrlap elküldése után lefutó függvények elejére regisztrálunk egy saját eseménykezelőt, ami így befolyásolni tudja majd a további működést. Fontos, hogy az elejére regisztráljunk, hiszen az alapértelmezett eseménykezelő küldi a levelet, és nekünk azelőtt kell közbelépnünk a folyamatba.

function wlcontact_form_alter($form_id, &$form) {
  if($form_id == 'contact_mail_user' && user_access('access administration pages')) {
    $form['toeditors'] = array(
      '#title' => 'Másolat az Example.com szerkesztőknek',
      '#type' => 'checkbox',
      '#description' => 'Másolat küldése a szerkesztőségi email címre is.',
      '#weight' => 9,
    );
    $form['copy']['#description'] = 'Másolat küldése a személyes email címre.';
    $form['submit']['#weight'] = 10;
    $form['#submit'] = array('wlcontact_mail_user_submit' => array()) + $form['#submit'];
  }
}

Felmerülhet a kérdés, hogy miként ismertem fel az űrlap azonosítóját és elemeit. Ilyen részletek érdekében nem szeretem a forráskódot böngészni, ezért egyszerűen a var_dump($form_id) és var_dump($form) használatával derítettem fel a struktúrát, illetve, hogy mit hol kell módosítanom, milyen nevű kulcsok vannak a tömbben. Ez éppen elegendő volt a céljaimra.

Nos, lássuk mit tudunk tenni, ha az űrlapot elküldik. Mivel a követelményünk az volt, hogy nem második levelet küldünk, hanem a contact modul által egyébként is elküldött levelet módosítjuk, nem tudunk azonnal levelet küldeni. Meg kell viszont jegyeznünk, hogy a szerkesztőségnek is el kell küldeni a levelet, mert erre még később szükségünk lesz. A submit függvények két paramétert kapnak, az űrlap azonosítóját és a beküldött értékeket. Most biztosak vagyunk az űrlap azonosítóját illetően, hiszen csak egy űrlaphoz kötöttük ezt az eseménykezelőt, ezért annak értékével nem foglalkozunk, csak azzal, hogy be legyen állítva. Amennyiben pedig az űrlap értékek között a szerkesztőknek való elküldést kérték, ezt egy statikus értékben megjegyezzük. Ha úgy hívjuk meg ezt a függvényt, hogy nem adunk meg semmilyen űrlap azonosítót, akkor fogjuk visszakapni a megjegyzett értéket.

function wlcontact_mail_user_submit($form_id = NULL, $form_values = array()) {
  static $toeditors = FALSE;
  if (isset($form_id)) {
    $toeditors = (bool) $form_values['toeditors'];
  }
  else {
    return $toeditors;
  }
}

Végül szükségünk van arra, hogy a megjegyzett értéknek megfelelően elhelyezzünk egy cc fejlécet a kiküldött levelekben. Erre a célra tavaly nyár óta a hook_mail_alter() használható. Ezt kell tehát már csak megvalósítanunk. Itt a levél részletes adatait kapjuk meg külön-külön paraméterekben. Most számunkra az az érdekes, hogy melyik levéllel van dolgunk. Szerencsére a contact modul fejlesztői okosan megkülönböztették a normál kapcsolat levelet a (beépített képességgel előállított) másolat levéltől, így csak a normál kapcsolat levélre tudunk koncentrálni. Itt ellenőrizni kell, hogy a korábban megjegyzett űrlap mező érték mi volt. Ha kérték a cc fejléc beállítását, akkor a fejlécek tömbjéhez adjuk ezt hozzá.

function wlcontact_mail_alter(&$mailkey, &$to, &$subject, &$body, &$from, &$headers) {
  if ($mailkey == 'contact-user-mail' && wlcontact_mail_user_submit()) {
    $headers['Cc'] = 'info@example.com';
  }
}

Voilá! Készen is vagyunk a kapcsolat űrlap funkcionalitásának kiterjesztésével, anélkül, hogy bármit módosítani kellett volna az alaprendszeren.

Hozzászólások

Illyés Edith képe

Én is használok egy ilyen funkciót, csak persze az én kódom nem ilyen szép :)

Az alapvető usability probléma szerintem az, hogy a contact modul nem menti az elküldött leveleket az adatbázisba. Mondjuk egy céges honlapnál nem megengedhető, hogy a levelek email formájában keringjenek a neten, ami aztán vagy megérkezik a címzetthez, vagy nem. Ezért a root@localhost-nak szoktam másolatot küldeni, hogy legalább valahol nyoma maradjon. De leginkább webform modult használok, ami ment az adatbázisba. Bár jobb lenne, ha pusztán ezért nem kellene egy kiegészítő modult beüzemelni.

Gondoltam már rá, hogy beküldöm feature request-ként, de nem tudom, patch nélkül van-e értelme feature request-eket küldözgetni :)

Hojtsy Gábor képe

Szerintem ez a levél mentős probléma már másban is felmerült. A hook_mail_alter() pedig adatbázisba is tudja menteni a levelet. Legalábbis ha tudod, hogy a te hook-od után már másik nem fut le, akkor ott van készen a kezedben az email tartalma, le tudod menteni.

Illyés Edith képe

Kerestem, de nem találtam kész megoldást. A lementés csak egy része a feladatnak, valahogy olvashatóvá is kell tenni a felhasználó számára az archivált üzeneteket, grafikus felületen.

Erre korábban az volt a megoldás, hogy a root@localhost-ra érkezett leveleket az esti biztonsági mentéssel újra kiküldtem a címzetteknek - mostanában pedig a webform modul. Rendszerint azért nem tudok gyorsan váltani az új core-ra mert meg kell várnom a webform frissítését. Olvastam másokról is, akik így vannak ezzel.

zoliky képe

Drupal 5.1 eseten eleg ha a fenti kodot a template.tpl.php fajlba rakom es modositom ?

Koszonom!

Hojtsy Gábor képe

Miből gondoltad? Nem egyértelmű a cikkben, hogy modulról van szó?

A demonstráció kedvéért nevezzük a modulunkat wlcontact-nak

zoliky képe

Elnezest kerek. Felteteleztem, hogy modulrol van szo.

Vegul letrehoztam egy modult, de csak az utolso ket reszet a kodnak raktam bele:

<?php
function contactlog_mail_user_submit($form_id = NULL, $form_values = array()) {
  static $toeditors = FALSE;
  if (isset($form_id)) {
    $toeditors = (bool) $form_values['toeditors'];
  }
  else {
    return $toeditors;
  }
}
 
function contactlog_mail_alter(&$mailkey, &$to, &$subject, &$body, &$from, &$headers) {
  if ($mailkey == 'contact-user-mail' && contactlog_mail_user_submit()) {
    $headers['Cc'] = 'sajatcim@example.com';
  }
}
?>

Ezt azert, mert szeretnem ha minden felhasznalora ervenyes lenne nem csak adminisztratoroknal.

Sajnos nem mukodik.

aries képe

Ha a működtető mechanzimusba akarsz belenyúlni – ahogy ezt a form is teszi – akkor modult kell írnod. Ha a megjelenést akarod megpiszkálni (a theme_ kezdetű függvényeken keresztül), akkor smink. Legjobban úgy tudod szerintem megtanulni, ha az alapokat elolvasod a kézikönyv oldalakon, megérted a hook_ és theme_ kezdetű függvények működését, és aztán kipécézel egy modult / sminket, és próbálod átírni a forrását. (Lehetőleg ne core modult válassz! :) )

Aries
http://aries.mindworks.hu

zoliky képe

Most korubelul ertem, hogy mukodik Gabor leirasa.
Igazabol valami mas megoldas kene nekem, ez a "CC" megoldas nem jo. A felhasznalo nem szeretnem ha tudna, hogy az e-mail uzenet hozam is elerkezik.

Egy uj levelet kene letrehozni. Gondolom ez mar kicsit bonyolult.

pp képe

Bcc miért nem jó? Azt ugyanis erre találták ki.

pp

vikicica22 képe

contact modul: Másolatot kérek gomb nekem csak user ként, jön elő. Sima anonymous user-ként nem jelenik meg. Elő lehet valahogyan csalni, hogy ott is látható legyen.

Illyés Edith képe

Ha kiteszed a gombot, más email címének megadásával bárki küldhet levélszemetet a honlapodon keresztül.

vikicica22 képe

Értem, és köszönöm!