Archiv des Autors: admin

Jetzt gilt’s: Rezepte aus WordPress importieren

Ich hab mir meine Tabelle mit den Rohdaten mal mit so etwa 30 Rezepten geladen, die sieht jetzt so aus:

rohdaten_screenshot

rohdaten_screenshot

Eigentlich brauchen wir nur die Felder titel und content, den URLsafe name können wir auch mit einer eingebauten Joomla-Funktion aus dem titel erzeugen:

$akt_name =JFilterOutput::stringURLSafe($akt_titel);

Aber das ist reine Geschmackssache. Jedenfalls wird die Foreach-Schleife jetzt ordentlich aufgebohrt, da kommt erstmal die Logik für die Belegung des JTable-Objekts rein. Meine drei Felder hab ich mir vorher natürlich auf Variable gelegt, ist übersichtlicher.

JTable-Objekt erzeugen, füllen und mit Insert wegschreiben

$article = JTable::getInstance(‚content‘);

$article->title            = $akt_titel;
        $article->alias            = $akt_name;
        $article->introtext        = $text;
        $article->catid            = 8;
        $article->created          = JFactory::getDate()->toSQL();
        //$article->created_by_alias = ‚Super User‘;
        $article->created_by = 839;
        $article->state            = 1;
        $article->access           = 1;
        $article->metadata         = ‚{„robots“:““,“author“:““,“rights“:““,“xreference“:““}‘;
        $article->language         = ‚*‘;

Dann fehlt nur noch die Logik zum Wegschreiben des befüllten Objekts, die hab ich aus dem Codebeispiel hier übernommen:

https://stackoverflow.com/questions/12643725/create-a-joomla-article-programatically?lq=1

Das sieht dann recht übersichtlich so aus:

// Check to make sure our data is valid, raise notice if it’s not.

        if (!$article->check()) {
            JError::raiseNotice(500, $article->getError());

            return FALSE;
        }

        // Now store the article, raise notice if it doesn’t get stored.

        if (!$article->store(TRUE)) {
            JError::raiseNotice(500, $article->getError());

            return FALSE;
        }

Das war schon die ganze Mechanik! Jetzt müssen wir nur noch die where-Klausel aus dem Select rausnehmen, die liest sich dann ganz einfach so:

$query = „SELECT * FROM 00_rohdaten;“;

Damit steppt unsere Foreach-Schleife brav durch alle Zeilen der Tabelle rohdaten durch und legt die neuen Artikel an. Kurzer Blick in die Beitragsübersicht:

neue_rezepte_screenshot

neue_rezepte_screenshot

Na bitte, da sind sie ja alle!  Auch im Modul „Die neuesten Rezepte“:

die_neuesten_rezepte

die_neuesten_rezepte

Die haben jetzt natürlich alle dasselbe Datum, nämlich heute, aber das anzupassen wäre jetzt schon Feinarbeit. Man könnte natürlich versuchen, das Erstellungsdatum aus WordPress zu übernehmen, das geht sicher auch, aber ich lass es jetzt mal gut sein. Noch ein kurzer Blick auf das alphabetische Inhaltsverzeichnis:

ivz_screenshot

ivz_screenshot

Alles OK, wir haben alles.

Fazit und Ausblick

So schlimm war das doch jetzt gar nicht, oder? Ich gebe zu, mit den Rohdaten aus dem Inselfischkochbuch war die Bereinigungsaktion vor dem Import recht einfach, einfach weil die Rezepte in den meisten Fällen aus sehr straightem HTML-Code bestehen, und den kann man mit wenig Modifikationen nach Joomla übernehmen.

Was mich aber noch ein bisschen fuchst: meine schönen Kategorien aus WordPress sind natürlich futsch, und ich hab eigentlich keine Lust, bei über 300 Rezepten die Kategorien nachträglich als Tags (Schlagworte) manuell einzufügen. Erinnern sie sich, ich hatte in diesem Beitrag meine WordPress-Kategorien als Schlagwortliste nach Joomla abgebildet. Das hatte soweit funktioniert, weil ich in WordPress keine verschachtelten Kategorien benutzt habe, keine ideale Lösung, aber besser als nix. Mal schauen, ob mir dazu noch was einfällt. Aber wir machen hier jetzt erstmal eine wohlverdiente Pause!

Beiträge aus WordPress holen: einige Vorüberlegungen

Nochmal kurz als Gedächtnisstütze: wir brauchen eigentlich nur drei Felder, und zwar:

$article->title            = 'This is my super cool title!';
$article->alias            = JFilterOutput::stringURLSafe('This is my super cool title!');
$article->introtext        = '<p>This is my super cool article!</p>';

Den title können wir straight aus der wp_contents übernehmen, das ist der post_title. Für den alias bietet sich das Feld post_name an, der wäre auch schon URLsafe. Und der introtext kommt aus dem Feld post_content. Sieht doch schon mal ganz gut aus.

Was nicht gehen wird

So leid es mir tut, aber Bilder und Links können wir leider nicht übernehmen, die müssen wir vor dem Import rausputzen. Warum? Ganz einfach, weil sich beide auf eine spezifische URL beziehen, die wir in Joomla nicht nachstellen können. Nochmal kurz zur Erinnerung, ein im Beitragseditor eingefügtes Bild sieht im Quelltext so aus:

caption_screenshot

caption_screenshot

Mit dem caption-Shortcode kann Joomla natürlich auch nix anfangen, der muss raus. Mit dem Link gehts uns nicht viel anders, wenn der so aussieht:

ahref_screenshot

ahref_screenshot

…muss eigentlich der ganze Tag weg bis auf den Text „Haferflockenmüsli a la Oma“, mal sehen ob wir das hinkriegen.

Was drinbleiben kann

Ich geh mal nur vom Inselfisch-Kochbuch aus, da muss jeder sehen, wie das bei ihm selber aussieht und die Ersetzungen ggf. anpassen. Ich hab nicht so sehr viele Formatierungen verwendet, das sind eigentlich nur die Überschriften h1…maximal h4, ab und zu mal eine nummerierte oder unnummerierte Liste, und gelegentlich ein <strong>, das kann alles drinbleiben. Shortcodes oder auch Gallerys oder sowas hab ich gar nicht verwendet, da muss nix passieren. Downloadlinks haben wir gar keine, und auch keine Gimmicks wie Slider oder sowas, das habe ich im Zuge der barrierefreien Restrukturierung alles eliminiert – gute Sache! Jetzt ist nämlich nur noch relativ sauberer HTML-Code im post_content übrig, den man in den meisten Fällen übernehmen können wird.

Zuerst mal: Export aus WordPress

Ich zieh mir  nur die oben genannten drei Felder post_title, post_content und post_name ab, Kriterien post_type = post und post_status = publish. Nachgedanke: die ID nehmen wir auch noch mit, die ist ja unique und macht uns im phpmyadmin das Leben leichter. Davon nehm ich mal nur eine Handvoll Datensätze zum Testen, nicht gleich alle über 300. Die schiebe ich in eine neue MySQL-Tabelle  und dann frisch ans Werk!

Nicht konvertierbare Tags rausschmeissen

Den caption-Shortcode mitsamt dem img-Tag werden wir so los:

replace_caption

replace_caption

Sorry, das gibts nur als Screenshot weil WordPress den Sourcecode verhunzt hat! Das ist übrigens nicht auf meinem Mist gewachsen, das hat Tante Google hergegeben – sehr praktisch.

Ebenso können wir dank fleissigen googlens die alt-Tags entfernen, aber den Linktext stehen lassen:

$text = preg_replace('#<a.*?>(.*?)</a>#i', '\1', $text);

Das wars aber auch schon mit den Bereinigungen! Die ganzen <hx> und so weiter können stehenbleiben, wir wollen ja die Überschriftsformatierungen und all das mitnehmen.

Testausgabe mit der PHP Bridge

Ich hab mir ein Miniformular gebastelt, das nur aus einem „absenden“ Button besteht, und zum Testen in die if (isset($_POST[‚absenden‘])){…} Bedingung  folgenden Code gepackt:

$db = JFactory::getDBO();

$query = „SELECT * FROM 00_rohdaten where id = 224;“;
$db->setQuery($query);

$result = $db->query();
$results = $db->loadObjectList();

foreach ($results as $zeile) :
echo $zeile->id;
echo $zeile->titel;
$text = $zeile->content;

//caption-shortcode mitsamt img-tag weg
$text = preg_replace(‚/\\.*\\[.caption\\]/‘, “, $text);

//a href weg, Linktext stehen lassen
$text = preg_replace(‚#<a.*?>(.*?)</a>#i‘, ‚\1‘, $text);

//bereinigten text ausgeben
echo $text;
//echo $zeile->content;
echo „<br>“;
endforeach;
In den Select muss natürlich der richtige Tabellenname rein, und die ID des Datensatzes, den man zum Testen ausgeben möchte. In der Foreach-Schleife werden dann die Ersetzungen für den Content ausgeführt und das Endergebnis ausgegeben, so hat man eine ganz gute Kontrolle darüber, wie der importierte Datensatz in Joomla aussehen wird.

Und wie gehts jetzt weiter?

Ich tendiere dazu, mir die bereinigten Rohdaten in eine separate Tabelle schreiben zu lassen, und aus dieser dann die Import-Logik zu füttern. Aber darüber muss ich noch ein wenig nachdenken, und dann gibts einen neuen Beitrag.

PHP Bridge für Joomla – wenn der Sourcerer an Grenzen stößt

Ich hab ja jetzt schon viel PHP mit dem Sourcerer eingesetzt, aber für komplexere Skripte ist das nur eine Krücke. Jetzt bin ich auf meinen Recherchen auf die PHP Bridge von Henry Schorradt gestossen, und die ebnet den Weg erheblich. Schaut mal hier auf Henrys Homepage:

http://www.henryschorradt.de/information/joomla/

Da ist bestens erklärt, wie das Ding einzusetzen ist, und hier auf youtube gibts auch noch ein informatives Video dazu – steile Sache!

Der Knackpunkt ist: man kann eigene PHP-Skripte im Template-Pfad ablegen und mit der Bridge als Menuitems zugänglich machen. Diese werden dann innerhalb der Component ausgeführt, d.h. sie füllen nur den Inhaltsteil. Das macht das Leben mit eigenen PHP-Scripten in Joomla doch deutlich leichter!

Das Ding wird meine Basis für den WP-Import, glaube ich. Ich geh mal weiter recherchieren…

So schnell geb ich nicht auf: Joomla-Artikel importieren, eine heisse Spur

Ich sitze ja hier immer noch auf über 300 Rezepten aus dem Inselfisch-Kochbuch und habe keine Lust, die per Copy&Paste nach Joomla reinzuschubsen, mehr zu dem Thema habe ich bereits in diesem Artikel erzählt. Jetzt bin ich bei Stackexchange auf einen vielversprechenden Ansatz gestossen, wie man einen Joomla-Artikel programmatisch erzeugen kann, mehr Infos hier:

https://stackoverflow.com/questions/12643725/create-a-joomla-article-programatically?lq=1

Im letzten Beitrag des Threads (Support Joomla 2.5 and Joomla 3.0) findet sich ein Sourcecode, der ohne weitere Modifikationen funktioniert. Ich zitier den mal hier rein:

if (version_compare(JVERSION, '3.0', 'lt')) {
    JTable::addIncludePath(JPATH_PLATFORM . 'joomla/database/table');        
}   
$article = JTable::getInstance('content');
$article->title            = 'This is my super cool title!';
$article->alias            = JFilterOutput::stringURLSafe('This is my super cool title!');
$article->introtext        = '<p>This is my super cool article!</p>';
$article->catid            = 9;
$article->created          = JFactory::getDate()->toSQL();
$article->created_by_alias = 'Super User';
$article->state            = 1;
$article->access           = 1;
$article->metadata         = '{"page_title":"","author":"","robots":""}';
$article->language         = '*';

// Check to make sure our data is valid, raise notice if it's not.

if (!$article->check()) {
    JError::raiseNotice(500, $article->getError());

    return FALSE;
}

// Now store the article, raise notice if it doesn't get stored.

if (!$article->store(TRUE)) {
    JError::raiseNotice(500, $article->getError());

    return FALSE;
}

(Quelle: https://stackoverflow.com/questions/12643725/create-a-joomla-article-programatically?lq=1)

Das sieht soweit gut aus, fehlt höchstens noch ein Eintrag für das Feld created_by (bei mir 839), und die metadata sehen bei mir in der Datenbank auch einen Hauch anders aus, aber das ist Kleinkram. Die catid wäre eigentlich immer 8 für Rezepte, das kann man fest verdrahten. Ich habs mal in den Sourcerer reingeschubst und ein paar mal laufen lassen, die neuen Artikel sind einwandfrei erzeugt worden.

So, jetzt gilts: wie kriegen wir unsere WordPress-Datensätze hier rein?

Eigentlich müssen wir nur diese drei Felder ordentlich füllen:

$article->title            = 'This is my super cool title!';
$article->alias            = JFilterOutput::stringURLSafe('This is my super cool title!');
$article->introtext        = '<p>This is my super cool article!</p>';

Schön wärs natürlich, wenn wir die WordPress-Kategorien als Tags mit übernehmen könnten, aber das wär nur ein extra-Zuckerl, jetzt kümmere ich mich erstmal um den Überbau, und der erfordert etwas Planung. Ich geh mal mein Denkmützerl aufsetzen und melde mich dann wieder mit einem neuen Beitrag.

 

Zusätzliche Felder in BreezingForms – nee, da mach ich lieber was eigenes

BreezingForms machts einem nicht leicht

Also, ich sag das ja ungern, aber nach einigen Tagen fruchtloser Recherche bin ich fast soweit zu sagen: ich gebs auf. Was ich wollte: mein BreezingForms-Formular um ein dynamisches Feld erweitern, in dem entweder die ID oder der Titel des Rezeptes erscheint, von dem aus das Formular abgeschickt wurde. Im Prinzip sollte das mit einem versteckten Feld funktionieren, aber das liess sich bei mir nicht speichern – eine Einschränkung der Free Edition? Bei Crosstec war nichts zum Thema zu finden, direkten Support gibts dort nur gegen Cash. In den Joomla-Foren hab ich auch nichts zielführendes gefunden, vielleicht war mir auch nur Tante Google nicht gewogen, aber ich mach da jetzt erstmal einen Break und denke über eine andere Lösung nach.

Doch was selbergestricktes?

Könnte ja eigentlich so schwer nicht sein. Ich muss ja noch nicht mal unbedingt eine E-Mail schicken, mir würde es reichen wenn die Rezeptbewertungen in einer eigenen Tabelle gesammelt werden. Aber eben mit dem Titel bzw. der ID des Rezeptes, sonst ist die ganze Mechanik nichts wert. Ich zieh mich mal zurück und gehe brainstormen. Schaun mer amal, was dabei herauskommt.

Wir fangen mal mit dem Sourcerer an

Ein kleines HTML-Formular ist schnell gestrickt, das sieht jetzt mal im ersten Ansatz so aus:

<form action=“#“ method=“post“>
Ihre Meinung ist mir wichtig – bitte bewerten Sie dieses Rezept!<br>
<!– Radio buttons für Wahl der Bewertung –>
<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>

Einfach zwei Radiobuttons und ein „absenden“-Button, mehr ist nicht dran. Der erste Ansatz zum Auswerten wäre dann dieser:

<?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

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

Was brauchen wir noch?

Die ID/den Titel des Rezepts. Na dann mal ran, das hatten wir alles so oder ähnlich schonmal, wir holen uns aus der JFactory die aktuelle Artikel-ID, und aus der Query das Feld title:

$article_id = JFactory::getApplication()->input->get(‚id‘);
$db=JFactory::getDbo();
$db->setQuery(’select title from #__content where id= ‚.$article_id.“);
$title=$db->loadResult();

Bitte, da haben wir doch alles was wir brauchen!

Jetzt könnte man zum Beispiel schon eine Mail zusammenbasteln:

// Die Nachricht
$nachricht = $article_id.“ „.$title.“ „.$note.“ „.$datum;
$nachricht = wordwrap($nachricht, 70);

// Send
mail(‚benutzer@example.com‘, ‚Rezeptbewertung‘, $nachricht);

Und das wars auch schon! In meinem Mailtodisk-Output kommt dabei Folgendes an:

To: benutzer@example.com
Subject: Rezeptbewertung
X-PHP-Originating-Script: 0:sourcerer_php_640dafb7b21f4d69df5677f28a8472eb

31 Schweinsbarten mit Sourcerer War prima 22-02-2018

Das ist genau das, was ich wollte, mir reicht dieser spartanische Output völlig, steht alles drin was ich wissen muss.

Wollen wirs noch in die Datenbank schreiben?

Klar wollen wir! Wir legen erstmal eine kleine Tabelle namens rezeptbewertungen an:

CREATE TABLE `jsite`.`rezeptbewertungen` ( `Datum` TEXT NULL , `artikelid` TEXT NULL , `artikeltitel` TEXT NULL , `note` TEXT NULL ) ENGINE = InnoDB;

Viele Wege führen nach Rom, ich hab mich für insertObject() entschieden. Dafür holen wir uns ein neues Objekt der stdClass und belegen es mit unseren Feldnamen aus der Tabelle (Groß- und Kleinschreibung beachten!). Die Values für den Insert haben wir ja schon parat, die liegen alle auf Variablen, die schreiben wir einfach rein:

$data = new stdClass();
//Objekt füllen
$data->Datum = $datum;
$data->artikelid = $article_id;
$data->artikeltitel = $title;
$data->note = $note;

$tablename = „rezeptbewertungen“;

//Insert ausführen
$db = JFactory::getDBO();
$db->insertObject($tablename, $data);
$result = $db->query();

//Erfolgsmeldung ausgeben
if ($result == true) {
echo ‚Datensatz erfolgreich gespeichert!‘;
}else{
echo ‚Fehler beim Insert!‘;
}

Das wars schon!

Bilanz

Wir haben jetzt eine Mechanik, die eine E-Mail aus den relevanten Daten des Bewertungsformulars baut und diese auch in unsere eigene Tabelle wegschreibt. Was noch fehlt: jetzt müsste man das ganze Spiel noch in den Override für die Artikel einbauen, und zwar mit der Abfrage, ob wir denn ein Rezept sind, weil nur dann das Bewertungsformular auch angezeigt werden soll. Dafür denke ich sollte man ein Modul basteln, in das das Formular mit der ganzen Mail- und Insert-Logik eingebaut wird, und dieses dann im default-Override an geeigneter Stelle einfügen. Wie das geht, habe ich im vorigen Artikel anhand des BreezingForm-Moduls schon beschrieben, das sollte ganz genau so funktionieren. Viel Spaß beim Ausprobieren!

Anmerkung zur E-Mail-Verschleierung

Falls in ihrem Mailoutput so etwas ankommt, hat die eingebaute E-Mail-Verschleierung von Joomla gegriffen:

To: Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein!     document.getElementById(‚cloakc1626f4c69a0a7ef61ea78b168523217‘).innerHTML = “;     var prefix = ‚ma‘ + ‚il‘ + ‚to‘;     var path = ‚hr‘ + ‚ef‘ + ‚=‘;     var addyc1626f4c69a0a7ef61ea78b168523217 = ‚benutzer‘ + ‚@‘;     addyc1626f4c69a0a7ef61ea78b168523217 = addyc1626f4c69a0a7ef61ea78b168523217 + ‚example‘ + ‚.‘ + ‚com‘;     var addy_textc1626f4c69a0a7ef61ea78b168523217 = ‚benutzer‘ + ‚@‘ + ‚example‘ + ‚.‘ + ‚com‘;document.getElementById(‚cloakc1626f4c69a0a7ef61ea78b168523217‘).innerHTML += ‚<a ‚ + path + ‚\“ + prefix + ‚:‘ + addyc1626f4c69a0a7ef61ea78b168523217 + ‚\‘>’+addy_textc1626f4c69a0a7ef61ea78b168523217+'<\/a>‘;
Subject: Rezeptbewertung
X-PHP-Originating-Script: 0:sourcerer_php_ec1d4b855a01f009702bc4b9389cf683

33 Kartofflebrei mit Title War nix 23.02.2018

Kann man auch ausschalten, dafür das Plugin Inhalt – E-Mail – Verschleierung deaktivieren, dann kommts wieder im Klartext, wenn man das will:

To: benutzer@example.com
Subject: Rezeptbewertung
X-PHP-Originating-Script: 0:sourcerer_php_71e38a5d68ac0a27865028e9085819ea

33 Kartofflebrei mit Title War prima 23.02.2018

Inhalt – E-Mail-Verschleierung

 

Hätt ich doch beinah übersehen: das Bewertungsformular

Das wär mir doch beinah durch die Lappen gegangen, wir brauchen natürlich noch das Feedback-Formular bei den Rezepten. Im Original-Inselfischkochbuch sieht das so aus:

bewertungsformular_screenshot

bewertungsformular_screenshot

Ich habs in WordPress natürlich mit dem Contact Form 7 angelegt, und dann das Plugin WP Post Signature genutzt, um das Formular automatisch am Ende jedes Beitrags einzufügen. Wollen mal sehen, was sich in Joomla daraus machen läßt. Ich hab mal einen ersten Versuch mit BreezingForms gestartet, schauen wir mal wie weit wir kommen.

Die Anforderungen im Klartext:

  1. das Formular soll am Ende jedes Rezeptes automatisch angehängt werden
  2. damit ich weiß, welches Rezept bewertet wurde, muss der Titel (oder wenigstens die ID) aus der E-Mail hervorgehen

Zu 1.: das hört sich einfacher an als es ist, denn eigentlich sind es zwei Anforderungen, wenn nicht sogar drei.

Das BreezingForms-Plugin

Um ein BreezingForms-Formular überhaupt in einem Artikel anzeigen zu können, muss man das BreezingForms-Plugin installieren. Das findet man, wenn man das BreezingForms-ZIP entpackt hat, unter plg_breezingforms.zip . Nach der Installation muss es noch aktiviert werden, das geht unter Erweiterunge->Module-> Suche nach „breezing“, Pluginname BreezingForms aktivieren. Erst jetzt hat man die Möglichkeit, ein BreezingForms Formular auch in einen Artikel einbinden zu können, und zwar  mit der Syntax:

{ BreezingForms : formularname }

Das fett markierte ist der Name des Formulars. Aber damit haben wir noch nicht viel gewonnen, schließlich müßte man diesen Code am Ende jedes Rezeptes manuell einfügen, und das war nicht die Anforderung.

Wie wärs stattdessen mit einem Modul?

Dafür braucht man laut crosstec noch das extra-Modul, mod_breezingforms.zip. Nach der Installation freigeben nicht vergessen! Dann kann man ein neues Modul vom Typ „BreezingForms“ anlegen und das gewünschte Formular angeben. Falls es nicht angezeigt wird kann es sein dass in den Moduloptionen in der Menüzuweisung „auf keinen Seiten“ steht, das muss man natürlich auf „auf allen Seiten“ ändern.

So, und was hat uns das gebracht?

Auch das Modul muss man erstmal per Hand am Ende jedes Rezeptes einfügen, das ist noch kein grosser Fortschritt aber gemach, gemach, das wird schon noch.

Warum nicht einen Override anlegen?

Weil bei einer Änderung der default.php das Bewertungsformular unter allen Artikeln angezeigt werden würde, nicht nur unter den Rezepten. Wir machen stattdessen mal ein alternatives Layout, das ist mir sympathischer.  Dafür kopiert man sich in den Ordner /templates/dein-templates/dein-template/html/com_content/article die Datei default.php unter einem eigenen Namen, ich nenns mal meins.php. In dieser Datei sucht man dann nach dem Eintrag

<?php echo $this->item->text; ?>

Darunter kopiert man die folgende Zeile:

<?php echo JHtml::_(‚content.prepare‘, ‚{loadposition bewertungsformular}‘); ?>

Jetzt geht man nochmal in das Modul für das Bewertungsformular zurück und ändert die Modulposition in bewertungsformular – Schreibweise genau einhalten!

Daraufhin muss man noch in einem beliebigen Rezept unter dem Reiter Optionen das Layout auf „meins“ stellen, dann wird das Formular nach dem Rezepttext auch angezeigt.

Das war jetzt aber auch noch nicht der Bringer?

Schließlich muss man auch das alternative Layout per Hand anwählen, ich geb zu, da ist noch nicht viel gewonnen, genauso schnell hat man ein Modul eingefügt. Das hängt jetzt alles daran, dass ich keinen Weg gefunden habe, ein Modul nur für eine Kategorie anzeigen zu lassen, und ich hab ein paar Stunden lang danach gesucht, bislang ohne Erfolg.

Ich hätte da noch so’ne Idee

Man könnte ja einen Override auf die default.php anlegen und abfragen, welche Kategorie der aktuelle Artikel hat, und abhängig vom Ergebnis das Modul anzeigen lassen oder nicht. Mal sehen, wie weit wir damit kommen.

In unserem Override der default.php für den Artikel suchen wir nach der Stelle:

<div itemprop=“articleBody“>
<?php echo $this->item->text; ?>
</div>

Danach schubsen wir eine Datenbankabfrage rein:

<?php
    $db=JFactory::getDbo();
    $article_id = JFactory::getApplication()->input->get(‚id‚);
    echo „aktuelle Artikelid= „.$article_id;
    
    $db->setQuery(’select catid from #__content where id= ‚.$article_id.“);
    $catid=$db->loadResult();
    echo „aktuelle catid= „.$catid;
    
    if ($catid == 8){
        echo JHtml::_(‚content.prepare‘, ‚{loadposition bewertungsformular}‘);
    }
    else {
        echo „Dies ist kein Rezept, Kategorie: „.$catid;
        }
    ?>

Was hab ich gemacht? Mir die ID des aktuellen Artikels geholt, diese in den Select auf die #__content reingeschubst und mir so die ID der Kategorie geholt. Rezepte sind bei mir Kategorie 8, das frage ich mit dem If ab und zeige das Formular nur an, wenn dies zutrifft. Das wars schon! Die Debug-Ausgaben kann man noch rausschmeissen, aber so funktionierts. Endlich wieder mal ein bisschen Spaß auf der Datenbank!

Was jetzt noch fehlt: die Übermittlung der Rezept-ID oder des Titels

Weil mir die ganze Menage nichts hilft, wenn ich nicht weiss zu welchem Rezept die Bewertung abgeschickt wurde. Da hilft nur Nachforschen beim BreezingForms-Support, aber dazu gibts einen neuen Beitrag.

Benutzerdefinierte Felder – im Beitrag anzeigen

Analog zu den Custom Fields in WordPress kann man auch in Joomla selbstdefinierte Felder zu den Artikeln anlegen. Ich bin da gleich mal reingerasselt, weil ich zu den Kochbüchern ein Feld „Unverbindliche Preisempfehlung“ haben wollte. Schauen sie mal unter Inhalte/Felder/Neu die Liste der Feldtypen an – da ist alles dabei, bloß keine Währung, der einzige verfügbare Zahlentyp ist Integer. Ein Datumsfeld sucht man auch erstmal, es versteckt sich hinter dem Feldtyp „Kalender“. Ansonsten stecken in den Feldtypen jede Menge Angaben, die ich für Spielerei halte, unter anderem auch ein Feldtyp „Farbe“, man sehe und staune:

rgb_feld

rgb_feld

Damit kann man sich im Frontend den RGB-Code der gewählten Farbe anzeigen lassen, wofür das auch immer gut sein soll.

Wenigstens kann man beim Anlegen der Felder angeben ob es sich um ein Pflichtfeld handelt, dann kriegt man beim Ausfüllen der Beiträge einen Hinweis, wenn was fehlt. Wo sich die Felder und die Feldinhalte wiederfinden lassen, dazu gibts einen:

Blick auf die Datenbank

Man kann auch noch Feldgruppen anlegen, aber das lassen wir mal aussen vor, sonst wirds zu kompliziert. Ich möchte jetzt einfach in einem Artikel den Wert eines benutzerdefinierten Feldes anzeigen, und zwar an beliebiger Stelle im Inhalt. Und – da bin ich ein bißchen eigen – ich möchte das auf relativ einfachen Weg in einem Sourcerer Codesnippet tun, ohne Overrides  und ohne eigens programmierte Module. Kann ja wohl nicht so schwer sein!

Dafür tun wir mal einen beherzten Griff in die Datenbank. Die relevanten Tabellen sind die #__contents, aus der brauchen wir die ID des Artikels, die Tabelle #__fields, aus der holen wir uns den Feldnamen und nach Belieben auch die Feld-ID, und schliesslich die #__fields_values, in der stecken schlussendlich die Werte der Felder. Ich habs mal kurz nach Access reingeschubst, da stellen sich die Beziehungen so dar:

fields_beziehungen

fields_beziehungen

Also, frisch auf, einen Join über alle drei Tabellen gebastelt, wichtig ist hier die item_id, die identifiziert unseren Artikel:

felder_join_alle_drei

felder_join_alle_drei

Der Select dazu sieht so aus und ist relativ straightforward:

SELECT Fields_values.field_id, Fields.name, Fields_values.item_id, Fields_values.value
FROM Fields INNER JOIN (Content INNER JOIN Fields_values ON Content.[id] = Fields_values.[item_id]) ON Fields.[id] = Fields_values.[field_id];

Wir wollen aber nur die Feldinhalte zum aktuellen Artikel ausgeben, ich nehm mal den mit der ID 22 und klemm noch eine Where-Klausel dran. Dann können wir uns auch den Join auf die #__contents noch sparen, die ID des Artikels ist ja erstmal fest.

SELECT Fields_values.field_id, Fields.name, Fields_values.item_id, Fields_values.value
FROM Fields INNER JOIN Fields_values ON Fields.[id] = Fields_values.[field_id]
WHERE (((Fields_values.item_id)=“22″));

Ergebnis wie erwartet:

felder_nur22

felder_nur22

Und jetzt kann man sich anhand der field_id oder dem field name ein benutzerdefiniertes Feld herauspicken, ich nehm mal den Namen:

SELECT Fields_values.field_id, Fields.name, Fields_values.item_id, Fields_values.value
FROM Fields INNER JOIN Fields_values ON Fields.[id] = Fields_values.[field_id]
WHERE (((Fields.name) Like „farbtest“) AND ((Fields_values.item_id)=“22„));

Schon haben wir den Datensatz mit dem richtigen Feldwert eingekreist:

felder_nurfarbtest

felder_nurfarbtest

Na bitte, geht doch!

Und wo kriegen wir jetzt die aktuelle Artikel-ID her?

Das ist eine berechtigte Frage, man kommt ihr aber mit folgender Konstruktion bei:

$article_id = JFactory::getApplication()->input->get('id');

Jetzt basteln wir uns wie gehabt ein neues Datenzugriffsobjekt in der Variablen $db, dazu muss man noch ein bisschen bei den doppelten und einfachen Hochkommata aufpassen und das Präfix #__ nicht vergessen, aber das sollte eigentlich problemlos klappen.:

$db = JFactory::getDBO();

$query = „SELECT #__fields_values.field_id, #__fields.name, #__fields_values.item_id, #__fields_values.value
FROM #__fields INNER JOIN #__fields_values ON #__fields.id = #__fields_values.field_id
WHERE (#__fields_values.item_id = „.$article_id.“ ) and (#__fields.name like ‚farbtest‚);“;

Die Variable $article_id schubsen wir in unsere Where-Klausel rein, den Namen des benutzerdefinierten Feldes auch, das kann man auch auf eine Variable legen, oder man verdrahtet es fest wie ich es getan habe. Das war schon der ganze Zauber!

Query zuweisen und ausführen:

$db->setQuery($query);
$result = $db->execute();

Objektliste laden, auch wenn wir nur 1 Zeile im result haben:

$results = $db->loadObjectList();

Ausgabe des Wertes aus dem Feld value mit foreach(), :

foreach ($results as $zeile) :
echo $zeile->value;
endforeach;

Das wars, da haben wir den Wert unseres benutzerdefinierten Feldes, und der kann an beliebiger Stelle im Artikel positioniert werden. Die anderen benutzerdefinierten Felder kann man natürlich auch mit dem Namen ansprechen, das geht ganz genau so wie hier vorgeführt.

Kleine Spielerei am Schluss: wenn wir schon einen RGB-Farbwert haben, möchten wir die Farbe auch sehen, ich mach mal ein Quadrat von 300 px Kantenlänge. Dann kommt in der foreach-Schleife noch eine Variablenzuweisung mit:

foreach ($results as $zeile) :
$aktuelle_farbe = $zeile->value;
echo $zeile->value.“<br>“;
endforeach;

Die verwenden wir jetzt in einer Div für das Farbquadrat:

echo „<div style=’background-color:“.$aktuelle_farbe.“; width: 300px; height: 300px;‘><h2>Aktuelle Farbe</h2></div>“;

farbquadrat

farbquadrat

Na siehste, haben wir doch noch eine Anwendung für den Feldtyp „Farbe“ gefunden!

Nachtrag

Ich bin gefragt worden, warum ich denn nicht ein alternatives Layout für die Anzeige der Felder angelegt habe und dann einfach dort an der richtigen Stelle mit:

<?php echo $this->item->jcfields[x]->value; ?>

das Feld mit der Nummer x einfüge. Ganz einfach: ich wollte den Feldinhalt innerhalb des Beitragstextes ausgeben, das ist der ganze Witz an der Sache. Das geht im Template nicht, da dort der Beitragstext als Ganzes mit <?php echo $this->item->text; ?> hereingeholt wird, und man keine Chance hat da innerhalb etwas zu positionieren. Ist der Sinn und Zweck der Übung jetzt etwas klarer?

Noch ein paar lose Endchen

Haupteinträge

Das fällt einem im Beitragseditor relativ gross ins Auge, aber was bedeutet eigentlich Haupteintrag ja/nein? Ist eigentlich ganz einfach. Man kann beliebige Artikel als Haupteinträge kennzeichnen, das ist so etwas wie eine übergeordnete Kategorie. Eine Anwendung: wenn man alle Haupteinträge unter einem Menüpunkt sehen will, erstellt man einen neuen Menüeintrag mit dem Menüeintragstyp Beiträge->Haupteinträge. Hier kann man auch einstellen, ob Artikel aus allen Kategorien oder nur aus einer bzw. mehreren ausgewählten Kategorien angezeigt werden sollen. Somit hat man eine Möglichkeit, besonders wichtige oder interessante Artikel auch kategorieübergreifend in einer Blogansicht zusammenzufassen.

Navigationspfad einfügen

Unter Erweiterungen->Module-> Neu -> Navigation – Navigationspfad versteckt sich ein Modul, das einen „Wo bin ich“-Navigationspfad an der gewünschten Layoutposition ausgibt. Nützlich bei verschachtelten Untermenüs!

Blanko-Modul für eigene Inhalte

Man hat unter Module->Neu->Eigenes Modul die Möglichkeit, ein Modul mit selbstdefinierten Inhalten zu erstellen. Ich finde, hier ist eigener PHP-Code, mit Hilfe des Sourcerer eingefügt, gut aufgehoben. Man kann es aber auch für öfter genutzte Texte, z.B. Copyrightvermerke oder dergleichen gut gebrauchen.

Joomla und die Bilder: ein stiefmütterliches Verwirrspiel

Man hat in Joomla prinzipiell drei Möglichkeiten, Bilder in einen Artikel einzufügen. Einmal als Inline-Element im Beitragseditor, wie wir das auch von WordPress her kennen. Dann gibt es noch das Einleitungsbild, entspricht in etwa dem Artikelbild in WordPress und wird in der Blogansicht über dem Artikel dargestellt. Und schliesslich noch das komplette Beitragsbild, das wie der Name schon sagt in der kompletten Ansicht des Artikels zu sehen ist.

Zu beachten ist in allen drei Fällen: Joomla hat keine Hilfsmechanik zum Bilderskalieren, jedes hochgeladene Bild landet in voller Pracht und Grösse im images-Verzeichnis und wird für die Anzeige auch in voller Größe geladen. Da, wo es WordPress ein bisschen übertreibt mit einem halben Dutzend und mehr passend zum Theme skalierter Bildkopien, tut Joomla von selber rein gar nix. Und ich hab lang gegooglet, aber Joomla-Extensions zum komfortablen Bilderskalieren beim Hochladen gibts anscheinend nicht als Public Domain, das sind alles Paid Downloads. Scheint so als wenn einem ohne zusätzliche Software nichts anderes übrig bleibt, als hochzuladende Bilder vorher per Hand auf ein vernünftiges Maß zu skalieren. Keine so richtig benutzerfreundliche Lösung!

Einleitungsbild und komplettes Beitragsbild

Diese legt man im Artikeleditor unter dem Reiter „Bilder und Links“ an, hier kann auch der Alt-Text und eine Bildunterschrift angegeben werden. Eine Option für das title-Tag hab ich nicht gefunden, aber wenigstens der Alternativtext ist vorgesehen… man ist ja schon für Kleinigkeiten dankbar.

Die hier vorgenommenen Einstellungen landen übrigens im Datensatz des Artikels in der #__contents-Tabelle, im Feld images, das sieht dann zum Beispiel so aus:

{„image_intro“:“images\/Appetitbrtchen.jpg“,“float_intro“:““,“image_intro_alt“:“Bernhard i\u00dft ein Appetitbr\u00f6tchen“,“image_intro_caption“:“Bernhard mit Appetitbr\u00f6tchen“,“image_fulltext“:“images\/avocado.jpg“,“float_fulltext“:““,“image_fulltext_alt“:“Maitre Philippe bereitet Avocadoh\u00e4ppchen zu“,“image_fulltext_caption“:“Avocadoh\u00e4ppchen“}

Braucht uns aber eigentlich nicht weiter zu kümmern, man kanns ja im Editor an der Oberfläche einstellen.

Beitragsbilder im Beitragseditor

Hier wirds ein bisschen undurchsichtig, was die Zuordnung der img-Attribute angeht, aber ich versuchs mal der Reihe nach aufzudröseln.

Wenn man ein Bild hochlädt und in den Artikel einfügt ohne irgendwelche zusätzlichen Informationen anzugeben, sieht der img-Tag erstmal so aus:

<img src=“images/Johannisbeeren.jpg“ alt=““ />

Der alt-Tag ist zwar da, aber leer. Wenn man das korrigieren möchte ist Handarbeit angesagt. Rechter Mausklick auf das Bild, Bild anwählen und hier was eintragen:

bild_kontextmenu

Hier kann man auch eine Anzeigegrösse für das Bild einstellen, aber das nur am Rande bemerkt. Wenn man sich jetzt den img-Tag anschaut sieht man Folgendes:

<img title=“Titel der Johannisbeeren“ src=“images/Johannisbeeren.jpg“ alt=“Beschreibung der Johannisbeeren“ width=“829″ height=“1091″ />

Ah so, die Bildbeschreibung mutiert zum Alt-Text, ja guck mal einer an! Und glauben sie aber nicht, dass man die img-Attribute jetzt auch im Mediamanager sehen könnte, da sind sie nämlich nicht drin. Man kann zwar beim Einfügen eines Bildes aus der Mediathek ebenfalls Bildattribute angeben:

mediam

mediam

Aber da kommt – Überraschung! – noch was anderes dabei raus:

<figure><img title=“Mediam Titel“ src=“images/Johannisbeeren.jpg“ alt=“Mediam Beschreibung“ />
<figcaption>Mediam Beschriftung</figcaption></figure>

Ach! Wobei die figcaption dann tatsächlich unter dem eingefügten Bild angezeigt wird:

mediam_beschriftung

Alles klar soweit? Glauben sie aber nicht, dass sie das alles auch im Kontextmenü des Bildes wiederfinden, da sieht natürlich aus wie gehabt, die Beschriftung taucht hier nicht auf:

mediam_kontextmenu

mediam_kontextmenu

Ich glaube, ich habe jetzt für einen Beitrag genug Verwirrung gestiftet, wir lassen das jetzt alles mal ein wenig einwirken. Zusammenfassend sei gesagt, dass das Ratespiel um vernünftige Alt-Texte und Bildattribute in Joomla noch schlechter zu durchblicken ist als in WordPress, und das will schon was heissen!

 

Ein Blick auf die Datenbank: Content und Konsorten

Einen Überblick über die in Joomla enthaltenen Tabellen kann man hier in der Joomla Documentation zum Thema Tables finden. Da werden allerdings nur die Tabellenstruktur und die Felddefinitionen aus der Datenbank zusammengefasst und keine weitere Erklärung dazu geliefert – das meiste davon könnte man auch im phpmyadmin herausfinden. Zur Tabelle contents heißt es zum Beispiel nur lapidar: „This table is used to store the content of your Joomla! core articles.“ Ah ja. Das hätte man sich evtl. selber denken können.

Also ist es vielleicht ganz interessant, mal ein bißchen hinter die Kulissen zu gucken, aber mit über 70 Tabellen macht es einem Joomla da nicht gerade einfach. Trotzdem, fangen wir mal an.

Die Tabelle contents

Wie wir am Anfang schon gesehen haben, macht Joomla im Gegensatz zu WordPress keinen Unterschied zwischen Beiträgen und Seiten, es ist zunächst mal alles Content. Das ist auch völlig legitim, da sehr fein gesteuert werden kann, ob ein Element einen Kategorieblog, einen einzelnen Artikel, ein Modul oder sonst etwas enthalten soll.

Fangen wir mal von vorne an:

id klar, AutoIncrement und Primärschlüssel

asset_id Fremdschlüssel auf die assets-Tabelle, dazu später mehr

title auch klar, der Titel des Artikels, wie er im Frontend angezeigt wird

alias sanitized Form des Titels für die sprechende URL

introtext und fulltext: da machen wir mal einen kleinen Break und eine Erklärung.

Introtext und Fulltext

Joomla bietet eine sehr komfortable Möglichkeit, im Artikeleditor ein „Weiterlesen“-Tag an beliebiger Stelle im Text einzufügen:

weiterlesen

weiterlesen

Das hat den Effekt, dass in der Blog-Ansicht nur der Text vor dem Tag angezeigt wird und ein Button zum (eben!) weiterlesen angezeigt wird:

weiterlesen_screenshot

weiterlesen_screenshot

Was da im Hintergrund auf der Datenbank passiert, ist recht kurios. Sobald man das Weiterlesen-Tag eingefügt hat, landet der Text vor dem Tag im Feld introtext, der Rest im Feld fulltext, der Artikeltext wird also auf zwei Datenbankfelder aufgeteilt. Nimmt man das Tag wieder heraus (Editor auf Textmodus umschalten und das Tag <hr id=“system-readmore“ /> löschen), wird wieder der gesamte Text im Feld introtext gespeichert, das Feld fulltext ist dann wieder leer.

Weiter gehts mit den Feldern der Tabelle content:

state entspricht dem post_status von WordPress, hier gilt für Joomla 3.x, soweit ich das eruieren konnte:

  • 0 = unpublished
  • 1 = published
  • 2 = archived
  • -2 = marked for deletion

catid ist die ID der Kategorie und ein Fremdschlüssel auf die categories-Tabelle.

created_by ist die UserID und ein Fremdschlüssel aus der #__users-Tabelle

Dann folgen noch ein paar Timestamps, deren Feldnamen recht selbsterklärend sind, und weiter hinten als kleines Zuckerl für SEOler ein  Feld hits, in dem die Anzahl der Zugriffe auf den betreffenden Artikel hochgezählt wird.

Lassen sie sich vom Feld images nicht aufs Glatteis führen, da steht nichts weiter drin, wenn sie kein Einleitungsbild oder komplettes Beitragsbild ausgewählt haben. Bilder, die sie im Artikeleditor eingefügt haben, stehen wie in WordPress gehabt als img-tag im Beitragstext, default Pfad ist das images-Verzeichnis: <img src=“images/avocado.jpg“ alt=““ />

Na, und was seh ich da? Der alt-Text ist leer, Schlamperei! Aber das ist eine andere Baustelle, und ich wette, das Verwirrspiel um die alt-Texte ist derselbe systemimmanente Bug wie in WordPress. Aber zur Bilderverwaltung in Joomla gibts ein andermal mehr!

Haben sie auch ein Deja vu?

Mit den hier vorgestellten Feldern aus der contents wäre es schon mal ein leichtes Spiel, einen einfachen WordPress-Beitrags-Datensatz zusammenzubauen. Vielleicht ist das der Grund, warum es eine Menge Konverter von Joomla nach WordPress schon gibt, googlen sie mal nach „joomla to wordpress converter“. Der Weg von WordPress nach Joomla ist da schon steiniger, weil die Joomla-Artikel wesentlich komplexer aufgebaut sind, aber darüber habe ich mich bereits in diesem Artikel ausgelassen. Ich bleibe dran…

Damit lassen wir es mal gut sein mit der Contents-Tabelle, und werfen als nächstes einen Blick auf die Bilderverwaltung in Joomla.