Von Drupal nach WordPress: der Vollständigkeit halber

Es kann ja rein theoretisch mal vorkommen, dass man existierende Drupal-Inhalte nach WordPress übernehmen möchte. Gehen wir mal davon aus, dass wir einen bestimmten Inhalltstyp aus Drupal als Blog-Beiträge nach WordPress exportieren möchte. Wir bleiben beim Kochbuch, der relevante Inhaltstyp ist „rezept“. Ich hab mal im Archiv gegraben und mir die Mechanik fürs grundlegende Anlegen eines WordPress-Posts geholt:

WordPress Post anlegen

// Beitragsobjekt anlegen
    $my_post = array();
    $my_post['post_title']    = 'Mein Titel';
    $my_post['post_content']  = 'Mein Content';
    $my_post['post_status']   = 'publish';
    $my_post['post_author']   = 1;

    // Beitrag in Datenbank einfügen
    //$neue_id = wp_insert_post( $my_post );

Mehr brauchts eigentlich nicht für den Anfang, der Titel und der Inhalt reichen mal für Demozwecke (Die Kategorien kommen später dran). Jetzt suchen wir uns aus Drupal die relevanten Daten zusammen.

Relevante Tabellen in Drupal

Zum einen die node-Tabelle, aus der brauchen wir vor allem die nid, den type und den title. Der content steckt in der field_data_body im Feld body_value, verknüpft wird über die nid im Feld entity_id. Der SQL sieht so aus:

SELECT field_data_body.entity_id, field_data_body.body_value, node.nid, node.type, node.title
FROM field_data_body INNER JOIN node ON field_data_body.[entity_id] = node.[nid];

Das Ergebnis sieht erstmal so aus:

node_fields
node_fields

Wir haben hier noch articles und pages mit drin, die filtern wir mit einem where type = ‚rezept‘ weg, dann passt die Sache.

Jetzt fehlen noch die Kategorien

Dafür brauchen wir zuerstmal die Tabelle taxonomy_term_data, in der stehen die id und Namen der Kategorien drin, und die vid, das ist der Index der verwendeten Taxonomy, das ist bei mir die 2. Das ergibt bei mir eine Liste mit 28 Einträgen, von denen ich nur die tid und den Namen brauche:

tid_name
tid_name

Die importiere ich mit dem phpmyadmin in unsere WordPress-Datenbank.

Schritt 1: Anlegen der Kategorien in WordPress

Dafür setzen wir uns ein kleines Plugin auf, das zunächst nicht mehr als ein  Formular mit einem Textfeld für den Namen der zu importierenden Tabelle und einen Start-Button enthält. Der Kern des Plugins ist ganz einfach. Auf der Variablen $akt_import liegt der Name der einzulesenden Tabelle mit den Kategorienamen. Durch die steppe ich zeilenweise durch und lege mit wp_create_category() die Kategorien neu an:

global $wpdb;
    $allezeilen = $wpdb->get_results( "SELECT * from ".$akt_import."");
    
    foreach ($allezeilen as $zeile){
        
        echo $zeile->name."<br>";
        wp_create_category($zeile->name);
    }

Das Ergebnis ist wie erwartet:

kat_in_wp
kat_in_wp

28 neue Kategorien. Von denen brauchen wir jetzt die WordPress-Kategorie-IDs, die stecken jetzt in der Tabelle wp_terms:

wp_terms
wp_terms

Schritt 2: verknüpfen mit den Drupal-Daten

Die wp_terms hole ich mir jetzt zu den Drupal-Tabellen nach Access rein. Dort habe ich mir inzwischen aus der node und aus der field_data_body eine neue Tabelle gebaut, die nur die nid, den title und den body_value enthält:

nid_title_body_value
nid_title_body_value

Die wird jetzt erstmal über die nid mit der taxonomy_index und diese über die tid mit der taxonomy_term_data verknüpft:

nid_tid_verknuepfung
nid_tid_verknuepfung

Dann hole ich mir die wp_terms mit dazu und verknüpfe über den name  mit der taxonomy_term_data:

mit_wp_terms
mit_wp_terms

Damit haben wir alle Felder, die wir für den Export nach WordPress brauchen, die term_id liefert uns die richtige Kategorie:

nodes_mit_term_id
nodes_mit_term_id

Das specken wir noch ein wenig ab und basteln uns eine saubere Export-Tabelle. Die enthält zunächst nochmal jeden Datensatz so oft, wie er Kategorien zugeordnet hat. Da ich in Drupal nur zwei Kategorien pro Datensatz hatte, taucht hier also jedes Rezept zweimal auf. Darauf setze ich eine Abfrage mit Gruppierung und nehme von der term_id einmal den letzten Wert und einmal den ersten Wert:

ersterwert_letzterwert
ersterwert_letzterwert

So, das wars. Diese Abfrage exportieren wir uns als CSV und holen sie uns in unsere WordPress-Datenbank rein. Für den tatsächlichen Import gibts aber einen neuen Beitrag.

Dropdown-Menüs: nur mit dem richtigen Theme

Als Drupal-Neuling stolpert man ganz schnell darüber, dass es erstmal nicht möglich ist, ein Dropdown-Menü einzurichten. Das ist im Standard-Theme Bartik und im ebenfalls mitgelieferten Theme Garland auch gar nicht vorgesehen! Man braucht ein Theme das diese Option von Haus aus mitliefert, eines wäre zum Beispiel Marinelli. Dann aber ist die Sache ganz einfach. Also, installieren sie sich Marinelli und Nice Menus und dann kanns losgehen.

Mega-Menu einschalten

Design->Marinelli->Einstellungen->Primary Menu settings Which kind of primary links do you want to use? auf Mega Drop Down stellen.

Dann ein paar Basic Pages mit Menüeinträgen erstellen, Reihenfolge und Anordnung können über Struktur->Menüs->Main Menu noch eingestellt werden.

untermenues
untermenues

Block positionieren

Den Block Nice Menu 1 auf die Position Utility Menu Top setzen.

nicemenu
nicemenu

Und so sieht das dann aus:

kochbuchmenu
kochbuchmenu

Drupal und die Bilder – ich geb ihm noch ’ne Chance

Die Bildverwaltung in Drupal ist etwas versteckt und gewöhnungsbedürftig, man kann aber letztendlich doch viel damit machen, deswegen schauen wir uns die Sache noch einmal genauer an.

Wenn man in Drupal ein Bild hochlädt, wird dieses skaliert und im Dateisystem mehrfach abgelegt. Standardmässig sind folgende Skalierungsoptionen aktiv:

Konfiguration->Medien->Bildstile

bildstile
bildstile

Man kann hier auch einen oder mehrere eigene Bildstile anlegen, ich hab mir hier mal einen mit der Breite 50 px und dem Effekt „Skalierung“ genommen und ihn Briefmarke genannt.

Bildanzeige: Steuerung über Inhaltstyp

Wann welcher der angelegten Bildstile verwendet wird, wird über die Inhaltstypen (!) gesteuert.  Suchen sie sich einen Inhaltstyp heraus, dem bereits ein Image-Field zugeordnet ist,oder legen sie es neu an. Ich nehm mal den „article“. Über Struktur->Inhaltstypen->Artikel->Anzeige verwalten gelangt man in ein Auswahlmenü, in dem man die Bildstile für die Anzeigemodi Standard und Anriss festlegen kann.  Ich ändere das mal im Anrisstext auf meinen selbstdefinierten Bildstil Briefmarke. Ergebnis in der gekürzten Ansicht:

vorschau_briefmarke
vorschau_briefmarke

In der Seitenansicht bleibt es beim „grossen“ Bild mit dem voreingestellten Format „Large (480×480)“.

vorschau_large
vorschau_large

Weitere Einstellungsmöglichkeiten

Über Struktur » Inhaltstypen » Article » Felder verwalten kann man bei EINSTELLUNGEN FÜR DAS IMAGE-FELD beim Punkt Anzahl von Werten einstellen, wie viele Bilder maximal zu einem Artikel hochgeladen werden können, Default ist hier 1. Wie die Bilder dann im Artikel angezeigt werden kommt auf den voreingestellten Bildstil an. Mehrere eingefügte Bilder werden untereinander angezeigt, auch wenn sie theoretisch nebeneinander Platz hätten, das finde ich weniger schön. ( Anmerkung: Man kann sicher ins CSS eingreifen, aber ich glaube, das lässt sich auch über Views lösen)

Man kann hier auch die Option „Bildtitel“ mit aktivieren, das ergibt dann später einen Hovertext bei der Bildanzeige auf der Webseite. Ebenso kann man ein Default-Bild einstellen, eine maximale und minimale Bildauflösung einstellen und eine maximale Upload-Grösse definieren.

Es hat auch Vorteile

Man ist es ja von WordPress her gewohnt, Bilder überall und in jeder gewünschten Grösse in einen Beitrag oder auf einer Seite einfügen zu können. Die restriktivere Steuerung über Bildstile in Drupal hat vielleicht den Vorteil, dass für einen bestimmten Inhaltstyp immer ein einheitliches Layout verwendet wird.  Ausserdem hat man hier im Gegensatz zu WordPress noch eine Chance, den Alt-Text und den Titel für jedes Bild im Nachhinein nochmal zu bearbeiten:

3_bilder
3_bilder

Wem das immer noch nicht genügt an Bild-Einstellmöglichkeiten, der braucht ein oder mehrere Zusatzmodule. Eines der am meisten empfohlenen ist Insert https://www.drupal.org/project/insert, ich habs aber auf meiner Testinstallation noch nicht zum Laufen gekriegt.

Bilder mit Views nebeneinander ausgeben

Neue View erstellen, z.B. „Bilder nebeneinander“. Anzeigen Inhalt of type Article, Create a page. Edit&Continue. Format Anzeigen Inhalt Fields, Felder Hinzufügen Inhalt (Bild), Bezeichnung leer machen, Bilddarstellung „Thumbnail“ auswählen. Wahlweise noch Fields hinzufügen Inhalt (Body), Bezeichnung entfernen. Das sollte dann in etwa so aussehen (der erste Artikel hat nur 1 Bild):

drei_bilder_nebeneinander
drei_bilder_nebeneinander

Ich sags ja, mit Views geht fast alles!

Was ich an Drupal 7 toll finde… und was weniger

Ohne Views geht gar nix – aber mit Views geht alles!

Und soweit ich das überblicke, hats ja Views in den Core von Drupal 8 geschafft. Aber Drupal 7 ohne Views ist noch nicht mal die halbe Miete, ohne das geniale (und komplexe) Abfragetool kommt man an das volle Potential von Drupal gar nicht ran.

Views ist allerdings mit einer steinigen, steilen Lernkurve behaftet, ohne viel Ausprobieren und Googlen geht da gar nichts. Je mehr man sich aber mit dem vielseitigen Tool beschäftigt, um so klarer wird es dass es nix gibt was nicht geht – oder fast nix.

Es lassen sich alle, aber auch wirklich alle Datenbankinhalte strukturiert abfragen und optisch ansprechend aufbereitet darstellen. Die Frage ist halt nur, wie lang man basteln und forschen muss bis zum gewünschten Ergebnis.

Ich würde mir wünschen, dass viele der öfter gebrauchten und populären Views-Anwendungen schon als Vorlagen mitgeliefert würden, so dass man nicht jedesmal das Rad neu erfinden muss.

Wirklich prima: die Inhaltstypen

Mit dem Konzept der benutzerdefinierten Inhaltstypen wird es einem leicht gemacht, die Inhalte auch komplexer Webseiten strukturiert zu präsentieren. Mit den entsprechenden Layout-Overrides gepaart hat man ein mächtiges Werkzeug, logisch separierte Inhalte auch nach den eigenen Bedürfnissen aufbereitet darzustellen. Das ersetzt locker die Multiblog-Fähigkeit wie man sie z.B. bei Joomla hat, die Verwaltung und Präsentation der Inhaltstypen läßt sich fein differenziert steuern und macht richtig Spaß.

Die API: braucht man gar nicht so oft

Weil man bei genauem Hinsehen oft feststellt, dass eine gewünschte Funktionalität in Drupal schon vorhanden ist bzw. mit Views relativ leicht zu realisieren ist. Das bisschen was ich von der API bislang gebraucht habe war eigentlich immer sehr straightforward und gut dokumentiert, besonders von den Möglichkeiten der Datenbankoperationen bin ich sehr angetan. Erhebt sich die Frage, ob das mit Drupal 8 so bleiben wird… die APIs sind komplett neu aufgestellt worden.

Mein Fazit: Drupal ist das CMS der Wahl für alte Datenbanker

Wenn man es mit vielen unterschiedlichen Inhalten zu tun hat und auch mit grossen Datenmengen, die man über ruhig auch komplexe Abfragen an die Web-Oberfläche bringen möchte, ist Drupal mit Views unschlagbar.

Wenn es in der Datenbank drinsteckt, kriegt man es in Drupal auch wieder heraus, und das oft auf erstaunlich einfachen Wegen. Keine Verrenkungen wie in WordPress, wo für alle möglichen Inhalte die wp_content herhalten muss, und auch kein Vergleich zu Joomla, das einem den Weg zu den Datenbankinhalten oft unnötig schwierig macht.

Da kann man es dann schon verschmerzen, dass man mit Views erst mal eine Runde üben muss, der geniale Funktionsumfang wiegt die wenig intuitive Bedienung leicht auf.  Ich bin mal gespannt, wie die Integration von Views in Drupal 8 gelungen ist!

Für die Kochbücher: ein eigener Inhaltstyp

Warum? Das wird man hier im Folgenden gleich noch sehen. Ich hab ja im Original-Inselfischkochbuch für jedes meiner Lieblingskochbücher einen eigenen Menüeintrag erstellt, das war fieselige Handarbeit und ausserdem statisch. In Drupal geht sowas wesentlich geschickter, wenn man es richtig anstellt.

Neuen Inhaltstyp „Kochbuch“ anlegen

Dabei nehmen wir gleich mal die Veröffentlichungseinstellung „Auf der Startseite anzeigen“ heraus:

inhaltstyp_kochbuch
inhaltstyp_kochbuch

Bei den Feldern fügen wir nur eins vom Typ Image hinzu:

kochbuch_felder
kochbuch_felder

Das wars auch schon. Jetzt legen wir mal zwei, drei neue Beiträge vom neuen Inhaltstyp „Kochbuch“ an und versehen sie mit etwas Inhalt.

Jetzt kommt der Knackpunkt: eine View

Struktur->Views->add new view „Meine Lieblingskochbücher“, Anzeigen Inhalt of type Kochbuch.

Create a page, create Menu link anhaken, Weigth nicht vergessen, Save&Exit.

Das erstellt uns einen neuen Menüpunkt und eine feine neue Seite, auf der alle Beiträge vom Typ „Kochbuch“ aufgelistet werden.

kochbuch_anzeige
kochbuch_anzeige

Das schicke daran ist: wenn ich jetzt einen neuen Beitrag vom Typ Kochbuch verfasse, erscheint der automatisch in der Liste, ich muss nicht mit einem eigenen Menüeintrag herumfusseln. Also, das nenne ich eine saubere Lösung!

Layout nach Wunsch anpassen

Wenn man jetzt noch das Layout für den Inhaltstyp Kochbuch ändern möchte, geht das auch wieder mit einem Override. Eine Kopie der (hoffentlich jungfräulichen) node.tpl.php anlegen, umbenennen in

node–kochbuch.tpl.php

und es kann losgehen. Cache leeren nicht vergessen!

Ein bisschen Feintuning – ein Gemischtwarenladen

Anrisstext in Blogansicht ausblenden

Mir genügt es völlig, wenn in der Blogansicht die Titel der Rezepte angezeigt werden. Teaser Text verwende ich nicht, weil mir das zuviel Arbeit ist, den müsste ich ja für jedes der über 300 Rezepte neu erstellen! Also blende ich den Body des Rezeptes in der Blogansicht komplett aus, das funktioniert mit folgendem Eintrag in meinem Template Override node–blog.tpl.php:

<div class="content clearfix"<?php print $content_attributes; ?>>
    <?php
      // We hide the comments and links now so that we can render them later.
      hide($content['comments']);
      hide($content['links']);
      //*****************Inhalt nur in der Full-Ansicht anzeigen
      if ($view_mode == 'full'){print render($content);}
    ?>

Das sieht dann so aus:

blog_ohne_teaser
blog_ohne_teaser

Überschrift „Weblogs“ auf der Blogseite ändern

Dafür legt man sich einen Override der der page.tpl.php an und benennt ihn mit page–blog.tpl.php. Dann nach dem Eintrag suchen:

<?php print $title; ?>

Diesen ersetzen durch:

<?php if (arg(0) != 'blog' && $node->type != 'blog') { print $title; } else {print "Alle Rezepte";}?>

Ergebnis:

alle_rezepte
alle_rezepte

Link „Blog von evi“ in der Blog-Ansicht ausblenden

Quick and dirty, aber funktioniert: die style.css des Themes um folgenden Eintrag ergänzen:

li.blog_usernames_blog.last
{
display:none;
}

Dann ist der Link weg.

blog_ohne_link
blog_ohne_link

Kategorien oben in der Full View anzeigen

An den Anfang  der node–blog.tpl.php folgende Zeile stellen:

<?php print render($content[‚field_tags‘]);?>

kategorien_oben
kategorien_oben

 

Erster Anlauf für das Bewertungsformular mit Template Override

Ich habe ja noch keinen vernünftigen Ansatz dafür gefunden, wie man ein Webform-Formular in ein Template einbindet, und bin ganz stark in Versuchung, den „kleinen Dienstweg“ zu nehmen und mein Formulärchen einfach per selbstgebauter PHP-Funktion einzubinden, so wie ich das in Joomla schon gemacht habe, näheres dazu in diesem Artikel.

Ich brauche Titel und/oder ID

Der Knackpunkt bei der Sache ist, beim Abschicken des Formulars brauche ich den Titel oder wenigstens die ID des Rezeptes, von dem aus das Formular verschickt wurde, sonst taugt das alles nix.

Ich probiers mal mit einem Template-Override

Der geht nämlich in Drupal gar nicht schwer. Um einen Override für den Inhaltstyp Blogeintrag anzulegen, geht man im Verzeichnis themes->[dein_theme]->templates hin und legt sich eine Kopie der Datei node.tpl.php an. Diese benennt man um in node–blog.tpl.php (doppelter Strich!), und jetzt kann man werken. Ich hab mal ein kleines Formular reingesetzt, und zwar nach nach der Div für den Content, also nach dem Block:

<div class="content clearfix"<?php print $content_attributes; ?>>
    <?php
      // We hide the comments and links now so that we can render them later.
      hide($content['comments']);
      hide($content['links']);
      print render($content);
    ?>

Hier sitzt jetzt mein kleines Formulärchen, das sieht so aus:

  <h2>Ihre Meinung ist mir wichtig – bitte bewerten Sie dieses Rezept!</h2>
 <form action='#' method='post'>
    <br>
    <input type='radio' name='Bewertung' value='War nix'>War nix<br>
    <input type='radio' name='Bewertung' value='War prima'>War prima<br>
    <input type='submit' name='absenden' value='Bewertung absenden'>
</form>

Damit hätten wir es schon mal an der richtigen Stelle platziert, zumindest wenn man das ganze Rezept anschaut:

bewertungsformular
bewertungsformular

Was mir weniger gefällt ist, dass das Formular so auch in der Blog-Ansicht nach dem Teaser auftaucht:

blog_mit_form
blog_mit_form

Aber darum kümmere ich mich später, jetzt holen wir uns erstmal den Titel des Rezeptes, der steckt nämlich praktischerweise in einer der verfügbaren Variablen – nachzulesen im Header der Template-Datei, ganz oben, da isser: $title.

Da haben wir doch schon alles: Mail kann verschickt werden

Und zwar mit dem selben simplen PHP-Scripterl, das ich schon in Joomla verwendet habe:

 <?php

        if (isset($_POST['absenden'])){
        if (isset($_POST['Bewertung'])){
            $note = $_POST['Bewertung'];
            echo 'Vielen Dank für Ihre Bewertung: '.$note;

             //hier kommt die Mechanik fürs Wegschreiben hin
             // Die Nachricht
                $nachricht = $title." ".$note;
                $nachricht = wordwrap($nachricht, 70);

                // Send
                mail('evi.s.leu@gmx.de', 'Rezeptbewertung', $nachricht);

        }
        else{
        echo 'Bitte eine Bewertung auswählen!';
        }
}
?>

Damit landet in meinem Mail-Output zum Beispiel:

To: evi.s.leu@gmx.de
Subject: Rezeptbewertung
X-PHP-Originating-Script: 0:node--blog.tpl.php

Bärli-Spezial - viele-Kräuter-Sauce War prima

Das erfüllt seinen Zweck, mehr brauch ich eigentlich gar nicht. Aber: es funktioniert nur in der ganzen Ansicht eines Rezeptes richtig!

Jetzt muss das Formular dringend aus der Blogansicht raus

Und zwar wirklich ganz dringend, weil es sonst nämlich E-Mails für alle 10 auf der Seite sichtbaren Rezepte verschickt! Ich glaube, ich hab da auch schon eine Lösung, aber dafür gönn ich mir eine kleine Pause und einen frischen Kaffee.

Na bitte geht doch: mit $view_mode

Ich hab mir die verfügbaren Variablen im Template nochmal genau angeguckt, und bin da auf die sehr praktische Sache mit dem view_mode gestossen:

$view_mode: View mode; for example, "full", "teaser".

Dann hab ich mein Formular samt Auswertungslogik in eine Funktion gepackt, die in meine Bibliothek evismodule.module reingestellt und rufe im Template jetzt nur noch die Funktion mit dem Parameter $title auf, und zwar nur im Full mode:

if ($view_mode == 'full'){
    bewertungsformular($title);
  }

Das war schon der ganze Zauber! Jetzt ist das Formular aus der Blogansicht draussen, in der ganzseitigen Ansicht drin, und verschickt brav nur eine einzelne E-Mail. Perfetto! Das hatte ich mir schwieriger vorgestellt.

Und was ist mit der Datenbank?

Ja klar wollen wir die abgeschickten Formulare auch in einer Tabelle speichern, das gelingt mit folgendem Code, der kommt direkt nach der mail-Anweisung rein:

$nid = db_insert('rezeptbewertungen')
                  ->fields(array(
                    'titel' => $titel,
                    'note' => $note,
                    'datum' => $datum,
                  ))
                  ->execute();

Das hab ich direkt aus der Drupal-Doku zum Thema Insert Queries übernommen. Sehr straightforward, gefällt mir sehr gut. Das setzt natürlich voraus, dass eine Tabelle namens rezeptbewertungen auch existiert und mindestens die drei Felder titel, note und datum hat, aber das sollte ja hinzukriegen sein.

Damit funktioniert unser Bewertungsformular so wie es soll, und ich mach hier einen Break.

 

Drupal Formulare mit Webforms

Der angesagte Formulardesigner für Drupal ist wohl Webforms, und ich fand den angenehm unkompliziert, das machen wir jetzt im Schnelldurchgang. Webform benötigt die ctools und Views, aber ohne die beiden ist ohnehin keine Drupal-Seite komplett, die sollten zur Standardausstattung gehören.

Nach der Installation findet sich unter Inhalt hinzufügen der neue Inhaltstyp Webform. Man hat hier zunächst mal die Option, einen neuen Menüeintrag für das Formular  anzulegen. Dann landet man im Fenster Form Components, hier sollte man zuerst mal unter E-Mails eine eigene E-Mail-Adresse angeben, sonst werden keine Mails verschickt.

email_hinzufuegen
email_hinzufuegen

Dann kann man unter Form Components ganz unkompliziert Formularfelder hinzufügen, ich lass es mal ganz schlicht beim Namen und der Nachricht:

zwei_form_felder
zwei_form_felder

Wenn man nichts weiter macht, kommt diese kleine Formular dabei heraus:

nachricht_an_evi
nachricht_an_evi

Man kann jetzt noch unter Form Settings/Confirmatioen Message einen deutschen Text zur Bestätigung eingeben. Was ich nicht gefunden habe: wie man den Linktext „Go back to form“ eindeutscht… Man kann zwar unter Form Settings ->Redirection Location No redirect anwählen, dann wird nach dem Versand die Formularseite neu geladen, aber dafür bekommt man dann eine Drupal-Meldung, die ist auch nicht schöner:

versandt
versandt

Aber das führt mir jetzt ein bisschen zu weit, ich schau ein andermal, ob sich dafür eine schönere Lösung findet.

Formulare in Blocks

Wenn man das Formular in einem Block nutzen will, muss man unter Form Settings->erweiterte Einstellungen „Available as Block“ anhaken, dann taucht das Formular in der Liste der vefügbaren Blocks auf. Ich wüsste jetzt zwar nicht wo ich das nutzen sollte, es sei aber der Vollständigkeit halber erwähnt.

Formulare in Inhalten

Man kann jetzt auch bei den Inhaltstypen unter dem neuen Punkt „Webform“ die Option „Enable webform Functionality“ für den aktuellen Inhaltstyp anwählen, dann kann man beim neu Anlegen eines Inhalts auch gleich ein neues Formular mit anlegen.

Es wird auch mitprotokolliert

Die abgeschickten Formulare werden übrigens in der Datenbank gespeichert, man werfe mal einen Blick auf die Tabelle webform_submitted_data.

Was ich noch nicht gefunden habe: ein Formular automatisch am Ende jedes Beitrags

Wofür ich das brauche? Für mein Bewertungsformular! Ich möchte doch gern am Ende jedes Rezeptes mein kleines Bewertungsformular haben, damit mir mein geneigtes Publikum die Meinung zum Rezept mitteilen kann. Dafür werde ich wahrscheinlich einen Layout-Override brauchen, und dafür gibts einen neuen Beitrag.

 

 

 

Meine Export-Datei, und wie man die Nodes jetzt tatsächlich anlegt

Ich hab mir die Tabelle taxonomy_term_data aus Drupal ins Access überspielt und mit meinen WordPress-Tabellen verknüpft, so komme ich an die tag-IDs. Das läuft genau wie bei der Erzeugung der Export-Datei in Joomla, nachzulesen hier in meinem Artikel über das Tag-Mapping. Das vorläufige Endergebnis habe ich mal auf 24 Rezepte beschränkt, aussehen tut es so:

24_rezepte
24_rezepte

ID, post_content, post_name und titel kommen aus WordPress, die tags 1..3 sind die gemappten tag-IDs aus Drupal. Den post_content hab ich schon bereinigt, da sind schon alle Links draussen und alle Caption-Shortcodes entfernt, wie das geht habe ich in diesem Artikel beschrieben.

Ich habs mal auf maximal drei Tags beschränkt, das reicht zum Vorführen. Diese Tabelle kommt jetzt in die Drupal-Database mit rein, und dann wollen wir mal.

Vorbereitungen

Voraussetzung für den Import ist, dass das Modul „Blogs“ aktiviert und ein Menüpunkt für die Blogseite erstellt ist, wie das geht hab ich in diesem Artikel beschrieben. Dann ändern wir in unserem Source den node type auf blog:

$node->type = 'blog';

Der Import mit db_query

Die Import-Tabelle lesen wir wie gehabt mit einem db_query ein, ich hab hier mal für den ersten Test noch eine where-Klausel mit drin, um die Sache erstmal auf einen Datensatz zu beschränken:

//***exporttabelle einlesen
        $query = db_query("SELECT * FROM 24_export where id = 205");
        $records = $query->fetchAll();

Mit einem Foreach() holen wir uns die einzelnen Zeilen der Query und legen uns die Inhalte auf Variable:

foreach ($records as $record) {
                
                $akt_titel = $record->titel;
                $akt_content = $record->post_content;
                $akt_alias = $record->post_name;
                $akt_tag1 = $record->tag1;

            // hier kommt die Action hin

}

Query-Ergebnisse in Variable einlesen

Diese Variablen passen wir dann in die Kreation des Nodes ein.

$body_text = $akt_content;

                $node = new stdClass();
                $node->type = 'blog';
                node_object_prepare($node);

                $node->title    = $akt_titel;
                $node->language = LANGUAGE_NONE;

                $node->body[$node->language][0]['value']   = $body_text;
                //$node->body[$node->language][0]['summary'] = text_summary($body_text);
                $node->body[$node->language][0]['format']  = 'full_html';
                $node->promote = 0; //nicht auf der Starseite
                
                // Alias erzeugen, post_name aus WP übernehmen
                $path = $akt_alias;
                $node->path = array('alias' => $path);
                
                /**Taxonomy Term zuordnen*/
                //id of your taxonomy term
                $tid = $akt_tag1;

                //add term to a node field
                //field_yourfield_name - machine name of your term reference field

                $node->field_tags[$node->language][0]['tid'] = $tid;
                /** end taxonomy term zuordnen */
                
                node_save($node);

Tags mitnehmen

Ich hab erstmal nur einen tag mitgenommen, aber das lässt sich leicht ausbauen. Sicherheitshalber frag ich auch noch ab, ob das tag-Feld nicht leer ist:

/**Taxonomy Terms zuordnen*/
                //id of your taxonomy term
                
                if ($akt_tag1 != ""){
                $tid1 = $akt_tag1;
                $node->field_tags[$node->language][0]['tid'] = $tid1;
                }
                
                if ($akt_tag2 !=""){
                $tid2 = $akt_tag2;
                $node->field_tags[$node->language][]['tid'] = $tid2;
                }
                
                if ($akt_tag3 !=""){
                $tid3 = $akt_tag3;
                $node->field_tags[$node->language][]['tid'] = $tid3;
                }
                
                //**end taxonomy terms zuordnen

Achtung: man muss in den Zeilen:

$node->field_tags[$node->language][]['tid'] = $tid3;

… den Parameter hinter $node->language leer lassen [], sonst werden die folgenden Tags nicht hinzugefügt, sondern überschrieben, so dass dann nur der letzte Tag zugeordnet ist.

Import komplett

Das wars jetzt aber – meine 24 Rezepte hat Drupal klaglos in den Blog importiert, die erscheinen auch brav im Block „Neueste Blogeinträge“:

neueste_blogbeiträge
neueste_blogbeiträge

Auch die Kategorien und die URL-aliase sind korrekt zugeordnet. Das nenn ich Spaß auf der Datenbank! 🙂

Jetzt lassen wir uns doch gleich mal das Inhaltsverzeichnis ausgeben:

ivz_24
ivz_24

Da hätte ich noch eine kleine Korrektur der Source für das Inhaltsverzeichnis nachzuliefern, das Array mit den Buchstaben braucht noch Anführungsstricherl, das sollte so aussehen, sonst wirft es PHP-Warnings:

$alfa = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');

Aber jetzt lass’mas gut sein, und nehmen eine Kaffeepause.

Drupal-Nodes programmatisch erzeugen

Node erstellen: ganz basic

Da ich ja nach wie vor auf über 300 Rezepten sitze, die ich nicht per Copy&Paste nach Drupal bringen will, hab ich mal nach Importmöglichkeiten gegooglet, und bin hier bei Group 42 fündig geworden. Der folgende Code erstellt einen Node vom Typ article, das funktioniert schon mal ganz gut. Was nicht so schön ist, ist dass die Sprache auf LANGUAGE_NONE gestellt wird, aber genau genommen stört das auch nicht weiter. Mal sehen, wie weit wir damit kommen. Hier der leicht modifizierte Code von Group 42:

/* Basic Node Creation Example for Drupal 7
        *
        * This example:
        * - Assumes a standard Drupal 7 installation
        * - Does not verify that the field values are correct
        */
        $body_text = '<h1>Text des neuen Nodes.</h1>';

        $node = new stdClass();
        $node->type = 'article';
        node_object_prepare($node);

        $node->title    = 'Node mit NID Evi full html';
        $node->language = LANGUAGE_NONE;

        $node->body[$node->language][0]['value']   = $body_text;
        //$node->body[$node->language][0]['summary'] = text_summary($body_text);
        $node->body[$node->language][0]['format']  = 'full_html';
        $node->promote = 0; //nicht auf der Starseite
        
        // Alias erzeugen, evtl. aus WP übernehmen
        //$path = 'content/programmatically_created_node_' . date('YmdHis');
        //$node->path = array('alias' => $path);

        node_save($node);

        echo "Node erzeugt, ID= ".$node->nid;

Besonders nützlich macht sich hier das:

node_object_prepare()

das nimmt einem schon einen Haufen Arbeit ab, indem es den neuen Node mit etlichen validen Werten vorbelegt, wer will kann das in der Drupal 7 API genauer nachlesen.

Eigentlich muss man jetzt nur noch den body text und den title mit eigenen Inhalten füttern, das könnte klappen. Das Format habe ich auf full_html gestellt, weil ich ja meine Überschriften-Headings aus WordPress übernehmen möchte.

Schön wärs natürlich, wenn man den alias auch gleich vernünftig anlegt, dafür könnte der post_name aus WordPress herhalten, aber das sehen wir dann schon noch, ob das was wird.

Kriegen wir die Kategorien als Tags hier auch mit rein?

Ja, kriegen wir! Und zwar mit folgender Ergänzung:

//id of your taxonomy term
        $tid = 8;

        //add term to a node field
        //field_yourfield_name - machine name of your term reference field

        $node->field_tags[$node->language][0]['tid'] = $tid;

Das macht man für mehrere Tags im Zweifelsfall einfach n mal. Damit sind wir bestens ausgerüstet und machen mal einen kurzen Break, weil ich erst in Access das Mapping von den WordPress-Kategorien auf die Drupal-Terms erstellen und mir eine vernünftige Export-Datei basteln muss.