Már meglévő tartalomtípus kiegészítése CCK field-el modulból

Nemrégiben a következő problémát kellett megoldanom: CCK mezővel kellett kiegészítenem egy tartalomtípust, de nem használhattam az admin felületet.
Erre azért volt szükség, mert egy elég nagy multisite felépítésű rendszerbe kellett bedolgozni, és olyan mezőtípusokra volt szükség, amit a CCK teljes egészében meg tud valósítani. Hozzátenném, hogy a views modul integrációt sem kell ebben az esetben magunknak elkészíteni, így azt is egyből lehet használni.

Kitaláltam egy leegyszerűsített feladatot, de szerintem a példával teljesen meg lehet érteni a működését, és rá lehet jönni miket is lehet még így beállítani:

A page tartalomtípust egészítsük ki egy autocomplete node referencia mezővel, amelynek segítségével korlátlan stroy típusú node-ot csatolhatunk page tartalomhoz. A label legyen elrejtve és teaser és teljes nézetben se jelenjen meg a node-on a kiválasztott tartalom.

Első lépésnek szükséges a modulnak egy info fájl, ebben fontos hogy megadjuk a nodereference modult függőségnek:

dependencies[] = nodereference

A tényleges importálás az install fájlban történik, még pedig a következő módon:
először a drupal_execute() fgv-el meghívjuk a CCK modul 'content_field_overview_form' form-ját, majd miután ez létrejött, a content_field_instance_update() fgv. segítségével beállítjuk a szükséges megszorításokat és a kimenetet.
Természetesen a modul un installálásakor törölni kell ezt a mezőt a content_field_instance_delete() fgv-el.

/**
 * Implementation of hook_install().
 */
function story_reference_install() {
  module_load_include('inc', 'content', 'includes/content.admin');
  module_load_include('inc', 'content', 'includes/content.crud');
 
  $form_state = array();
 
  $form_state['values']['_add_new_field']['label'] = t('Stories');
  $form_state['values']['_add_new_field']['weight'] = 1;
  $form_state['values']['_add_new_field']['field_name'] = 'page_stories';
  $form_state['values']['_add_new_field']['type'] = 'nodereference';
  $form_state['values']['_add_new_field']['widget_type'] = 'nodereference_autocomplete';
  $form_state['values']['submit'] = t('Save');
 
  drupal_execute('content_field_overview_form', $form_state, 'page');
 
  $type = content_types('page');
  $field = $type['fields']['field_page_stories'];
  $field['multiple'] = 1;
  $field['referenceable_types'] = array('story' => 'story');
  $field['display_settings']['label']['format'] = 'hidden';
  $field['display_settings']['teaser']['exclude'] = 1;
  $field['display_settings']['full']['exclude'] = 1;
 
  content_field_instance_update($field);
}
 
/**
 * Implementation of hook_uninstall().
 */
function story_reference_uninstall() {
  module_load_include('inc', 'content', 'includes/content.crud');
 
  content_field_instance_delete('field_page_stories', 'page');
}

Először be kell tölteni a content.admin és a content.crud állományokat, mert a szükséges fgv-ek ezekben szerepelnek, majd a $form_state tömböt kell feltölteni. Itt igazából azt a tömböt kell előállítanunk mint amit a submit fgv az admin felület használatakor kap meg. Ezért szükséges az ['_add_new_field']['label'] = t('Stories'); stb definiálása. A súlyt is átállíthatnánk amire akarjuk és csak a példa miatt node referencia típusú a field, azokat is lecserélhetjük amilyenre nekünk kell.
A drupal_execute() fgv-nek viszont ez esetben, nem csak a form nevét ('content_field_overview_form') és az előállított tömböt ($form_state) kell átadni, hanem a 'page' string-et is, ami a kiegészítendő tartalomtípus neve. Ha megnézzük a content.admin fájlban a content_field_overview_form() fgv-t akkor láthatjuk, hogy ezt a paramétert még várja.

Ezután az update form-ot kell megfelelően kitölteni, itt tudjuk beállítani pl. a megengedett értékek számát, vagy választható tartalomtípusokat és a megjelenési beállításokat is. Ezek mindegyik CCK mező típusnál eltérőek lehetnek, jelen esetben én ezeket állítottam be.
Itt viszont nem a $form_state-et kell előállítani, hanem a $field-et, hogy azt át tudjuk adni a content_field_instance_update() fgv-nek. Fontos, hogy amikor a field-et betöltjük, akkor már nem a megadott 'field_name' értéket kell használnunk, hanem prefix-elni kell a 'field_' string-gel, úgyhogy esetünkben 'page_stories'-ból 'field_page_stories' lett.

Az uninstall során elegendő betölteni a content.crud állományt mert ez tartalmazza a content_field_instance_delete() fgv-t. Paraméterben itt is figyelni kell a mező nevének prefix-ére ('field_'), második paraméterbe pedig a szerkesztendő tartalomtípus nevét kell megadni.

Remélem ebből a példából érthetően lejön, hogy ezzel a módszerrel mit is lehet megvalósítani és hogy mire jó. Ha más mezőkkel próbálkozunk akkor azokat is könnyen fel lehet vinni így, akár egy olyat is, hogy a modulban létrehozunk imagecache preset-eket és imagefield-el egészítjük ki a tartalomtípust aztán beállítjuk, hogy a teaser-ben az thumbanil preset látszódjon úgy hogy linkeljen a node-ra, míg a teljes nézetben a normal preset amire ha rákattint a felhasználó akkor lightbox2-ben jelenjen meg... stb.

Ha bármilyen kérdés vagy észrevétel van, akkor nyugodtan jelezzétek!

Features?

Ez a megoldás miben különbözik attól a kódtól, amit Features segítségével összeklikkolhatunk? Másképp: ha „csak” ennyi a feladat, akkor miért nem jó a Features használata?

(Oké, meglevő, ráadásul multisite esetén lehet, hogy plusz modul, meg fejfájás, meg minden, de egyszerűbb esetekben meglátásom szerint hatékonyabbnak tűnik a Features használata.)

Azért, mert az eset

Azért, mert az eset speciális:

  • létező tartalomtípust kell módosítani
  • multisite rendszerben
  • a tartalomtípus modulból lett létrehozva, kihagyva a CCK-t, a Drupal hook-ok segítségével

Ha mindezeket figyelembe vesszük, akkor a features használata ebben az esetben csak bonyolítaná a dolgot, és nem egy ~50 soros modullal úsznánk meg.

Ha egyszerűbb lenne a szitu akkor persze tökéletes megoldás lenne a features is, bár ebben az említett rendszerben nincs, és egy ideig nem is lesz feltelepítve.