Archiv der Kategorie: Inhaltstypen

Seitenaufrufe anzeigen mit dem Statistik-Modul

Man kann auch in Drupal anzeigen lassen, wie oft eine Seite schon aufgerufen wurde, das ist nur ein bisschen versteckt. Zuerst einmal muss das Statistik-Modul aktiviert werden, das geht unter Module/Statistics. Anhaken, Speichern, dann unter Konfiguration die Option Inhaltsabrufe zählen aktivieren. Dann in die Berechtigungen gehen und falls gewünscht unter Statistics/Inhaltsaufrufe sehen diese Option auch für Gast und authentifizierten Benutzer aktivieren. Das sollte es gewesen sein.

Kurzer Blick auf die Datenbank: Drupal protokolliert jetzt in der Tabelle node_counter mit, welche nid wie oft, wie oft am aktuellen Tag und wann zuletzt aufgerufen wurde:

node_counter
node_counter

Die Anzahl der Aufrufe sollte jetzt auch unterhalb jedes Inhalts erscheinen.

aufrufe
aufrufe

Nicht ins Bockshorn jagen lassen, beim ersten Aufruf erscheint hier noch nichts, klassischer Offset-by-one-Fehler. Erst beim zweiten Aufruf der selben Seite taucht der Zähler auf.

Komplettes Zugriffsprotokoll

Man kann auch unter Konfiguration/Statistik das komplette Zugriffsprotokoll aktivieren, aber da sollte man sich auf einer Seite mit einigermassen Traffic auch sicher sein, dass man diese Informationen auch wirklich braucht, sonst bläht das die Tabelle accesslog auf wie nix. Mir reicht die kleine Lösung oben, die in der node_counter protokolliert wird, völlig aus.

Anzeige der beliebtesten Inhalte

Dafür gibts einen fertig konfigurierten View „Beliebte Inhalte“, der aktiviert werden kann, wenn das Statistik-Modul eingeschaltet ist. Das sieht dann so aus:

beliebte_inhalte
beliebte_inhalte

Ich habe zwar noch nicht rausgefunden, ob und wie man die Anzahl der angezeigten Inhalte steuern kann, aber das ist doch schon mal ganz nett. Man kann sich natürlich auch einen individuellen View basteln, in dem man die Anzahl der anzuzeigenden Inhalte selber konfigurieren kann, die Anzahl der Aufrufe ist über das Feld „Content statistics: Total views“ verfügbar.

Drupal Bewertungsformular mit AJAX

Was in WordPress so schön funktioniert hat, sollte doch auch in Drupal zu machen sein: ein Bewertungsformular, das sich beim Abschicken einer neuen Bewertung selbst updated, eine genaue Beschreibung dazu findet man in diesem Artikel im Blog zum schwarzen Pinguin. Man kann Noten von sehr gut bis ungenügend vergeben, und es gibt einen Button zum Abschicken der Bewertung. Dazu werden die evtl. bereits vorhandenen Bewertungen und die Durchschnittsnote angezeigt, aussehen tut das Ganze so:

bewertungformular1
bewertungformular1

Voraussetzungen in Drupal

Ich werde dieses Formular nur für einen ausgesuchten Inhaltstypen anlegen, ich nehm mal die Artikel. Dazu brauchen wir einen Template Override – das hört sich schlimmer an als es ist.

Um die Bildschirmanzeige für alle Inhalte vom Typ Artikel zu ändern, klemmt man sich aus dem Verzeichnis ../themes/[dein theme]/templates die node.tpl.php und macht eine Kopie davon. Diese benennt man um in node–article.tpl.php (doppelter Bindestrich!). Dann sucht man sich die richtige Stelle nach dem Content aus, das ist in meinem Fall 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);
?>
</div>

Da ich das Formular nur in der Einzelansicht anzeigen möchte, füge ich hier eine if-Abfrage ein, die sieht erstmal so aus:

<?php
if ($view_mode == 'full'){

echo "<h1>Hier kommt das Formular hin</h1>";
}
?>

Cache leeren nicht vergessen, und nachgucken ob der Text an der richtigen Stelle angezeigt wird. Dann kann man hier den Funktionsaufruf reinpacken:

if ($view_mode == 'full'){

el_bew_ajax();

}

Ein eigenes Modul für das Formular

Das Formular selber packe ich in ein selbstgebautes Modul, zur Erstellung eines einfachen Moduls in Drupal kann man in diesem Artikel nachschlagen. Zuerst kommt mal das HTML für die Anzeige des Formulars rein, das wird in eine Funktion gesteckt:

function el_bew_ajax(){

echo '<div style="border:1px dotted #000; text-align:center; padding:10px;">';
echo '<h4>Dir gefällt dieser Beitrag?</h4>';
echo '<p>Dann bewerte ihn!</p>';
echo '</div>';

echo " <form action = '' method='post'>";

echo "<fieldset>
<div id = 'noten' class = 'noten' style = 'border:2px solid blue; padding :4px;'>
<input type='radio' name='note' value='1'>sehr gut
<input type='radio' name='note' value='2'>gut
<input type='radio' name='note' value='3'>befriedigend<br>
<input type='radio' name='note' value='4'>ausreichend
<input type='radio' name='note' value='5'>mangelhaft
<input type='radio' name='note' value='6'>ungenügend

<input type ='button' name = 'absenden' class = 'bew-button' value = 'abschicken' onclick='el_bew_ajax()'/>
</div>
</fieldset>";
echo "</form>";


}//ende function el_bew_ajax

Das habe ich 1:1 aus der oben zitierten WordPress-Lösung kopiert, funktioniert hier genauso. Das Javascript wird bei Klick auf den ‚absenden‘-Button aufgerufen, dazu gleich mehr.

Eine Tabelle für die Bewertungen

Auch diese sieht genau wie in der WordPress-Lösung aus und enthält drei Felder, eine Autowert-ID, ein Int für die nid und ein Int für die Note:

drupal_bewertungen
drupal_bewertungen

Die Logik für die Anzeige der bereits vorhandenen Bewertungen

Diese musste ich nur ein wenig auf Drupal-Verhältnisse anpassen, die Datenbankabfrage funktioniert hier mit db_query. Die aktuelle Beitragsid ist ein bisschen sperrig abzufragen, da suche ich noch eine hübschere Lösung:

//nid des aktuellen Beitrags bestimmen und in span schreiben
$nid = 0;
if (arg(0) == 'node' && is_numeric(arg(1))) {
$nid = arg(1);
}
echo 'NID dieses Beitrags: <span id = "beitragsid">'.$nid.'</span>';

//******aktuelle Benotungen abholen und Durchschnitt berechnen


$result = db_query('SELECT * FROM {bewertungen} WHERE nid = '.$nid.'');
$gefunden = $result->rowCount();


$durchschnitt = 0;
foreach ($result as $record) {
$durchschnitt = $durchschnitt + $record->note;

}
if ($gefunden != 0){ 
$durchschnitt = $durchschnitt / $gefunden;
}
echo "<span id = 'ausgabe'>".$gefunden." Bewertungen gefunden, Durchschnitt: ".$durchschnitt."<span>";

Das Javascript

…wird  am Anfang der .module-Datei eingebunden, und zwar so:

function ajax_el_init() { 

drupal_add_js(drupal_get_path('module', 'ajax_el') . '/test_ajax_el.js');

}

Die js-Datei liegt bei mir einfach im selben Verzeichnis wie das Modul. Sie sieht wird in einen Wrapper eingebunden, damit man $ für jQuery verwenden kann:

(function ($) {
function el_bew_ajax(){

//Hier kommt der Code

}//end function el_bew_ajax
})(jQuery);

Die ganze Funktion für den Ajax-Call sieht folgendermassen aus:

(function ($) {
function el_bew_ajax(){


//Beitragsid aus span holen
var akt_id = document.getElementById("beitragsid").innerHTML;

//Note aus den Radiobuttons holen
var akt_note = $("input:radio[name=note]:checked").val();

//Debug-Ausgabe
//alert(akt_note + ' ' + akt_id);

//Check ob keine Note angewählt, Abbruch
if (typeof akt_note === 'undefined'){
alert('Bitte eine Note wählen!');
return;}

//***********************ajax-call
if (window.XMLHttpRequest)
{
// AJAX nutzen mit IE7+, Chrome, Firefox, Safari, Opera
xmlhttp=new XMLHttpRequest();
}
else
{
// AJAX mit IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("ausgabe").innerHTML = xmlhttp.responseText;

}
}
xmlhttp.open("GET","../sites/all/modules/ajax_el/callback_ajax_el.php?id="+akt_id+"&note="+akt_note,true);

xmlhttp.send();



//**********************end ajax call
}//end function el_bew_ajax
})(jQuery);

Ich hole mir am Anfang die nid des Beitrags und die aktuelle Note aus dem Formular und gebe eine Meldung aus falls keine Benotung angewählt wurde.

Die Funktionalität für den Ajax-Call ist die selbe wie die, die wir schon für den Ajax-Autocomplete in diesem Beitrag verwendet haben, das drösel ich hier jetzt nicht nochmal auf.  Der einzige Unterschied ist, dass hier am Ende zwei Parameter statt nur einem an die Callbackfunktion übergeben werden.

Die Callback-Funktion

ist auch recht einfach. Ich hole mir die zwei Werte für die Note und die nid des Beitrags, mache einen Insert auf die Tabelle bewertungen und berechne den neuen Durchschnitt sowie die Anzahl der Bewertungen. Zurückgegeben werden die neuen Werte, die kriegt unser Script als  response und schreibt sie in die div ‚ausgabe‘ im Formular.

$nid = '';
if ( isset($_GET['id']) )
{
$nid = $_GET['id'];
}
$note = '';
if ( isset($_GET['note']) )
{
$note = $_GET['note'];
}

$pdo = new PDO('mysql:host=localhost;dbname=druneu', '******', '*******');

//neue Note erstmal einfügen
$sql = "INSERT INTO bewertungen (nid, note) VALUES (".$nid.",".$note.")";
$neu = $pdo->query($sql);

//Suche nach aktueller nid
$sql = "SELECT * FROM bewertungen where nid = ".$nid."";
$records = $pdo->query($sql);
$gefunden = $records->rowcount();

$durchschnitt = 0;
foreach ($records as $row) {

$durchschnitt = $durchschnitt + $row['note'];
}
if ($gefunden != 0){ 
$durchschnitt = $durchschnitt / $gefunden;
}
echo $gefunden." Bewertungen vorhanden, Durchschnittsnote = ".$durchschnitt;

Das war schon der ganze Zauber! Man kann jetzt noch die Durchschnittsnoten runden und per switch case die entsprechenden Bezeichnungen vergeben (1=sehr gut… 6=ungenügend), aber das ist Feintuning, das spare ich mir jetzt.

Aussehen tut das Ganze jetzt so:

bewertungsformular2
bewertungsformular2

Tipp: damit man sich beim Testen nicht schwarz ärgert wenn was nicht gleich funktioniert: Cache leeren nach jeder Script-Änderung!

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.

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!

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!