Wir bauen uns ein eigenes RSS-Modul für xt:Commerce

Heute gibt es mal wieder etwas sehr nettes bei seo-geek.de. Wir programmieren uns unser eigenes RSS-Feed AddOn für das GPL-Shopsystem xt:Commerce. Oft wird gefragt, wie man wohl aus seinen neuesten Artikeln, welche man im xt:Commerce Shop einpflegt einen echten RSS-Feed bauen kann. Was bringt uns das? Zu einem bieten wir unserem Shop-Kunden einen gewissen Mehrwert, da dieser im Falle von Produktaktualisierungen nicht immer auf die Webseite surfen muss, sondern diese Nachricht direkt in seinem Newsreader angezeigt bekommt. So sparen wir uns ebenfalls die Gebühren von Newsletter-Diensten wie z. B. cleverreach.de. Wie können wir aber nun den RSS-Feed für xt:Commerce bewerkstelligen?

Möglichkeiten und Ideen eines RSS-Feeds für xt:Commerce

Eine Alternative ist natürlich im Hintergrund einen WordPress-Blog laufen zu lassen und diesen im Shop verlinken. Dass dies mit einem Gewissen Grad an Mehrarbeit verbunden ist dürfte klar sein. Deswegen wollen wir uns das ganze selber basteln. Dazu benutzen wir weigehenst xt:Commerce-eigene Funktionen.

Wir werden das ganze auch nicht mit einem einzigen Post perfekt hinbekommen. Ich werde das als kleines Projekt nebenher laufen lassen und Stück für Stück (vielleicht auch mit einigen Gastbeiträgen - bei Interesse gerne bei mir melden) bis zur Produktreife bringen. Geplant habe ich die RSS-Ausgabe für folgende Funktionen:

  • Anlegen, Verändern und Löschen eines Produktes
  • Anlegen, Verändern und Löschen einer Kategorie
  • Ausgabe vom Produktfoto, Beschreibung und Namen des Produktes

Wie gehen wir hierbei vor? Ich möchte ja, dass meine Leser auch dahingehend einen Mehrwert bekommen, dass man auch die Technik dahinter versteht, also das ganze Wie, wo und warum? Keine Angst, für die die das nicht wissen wollen biete ich am Ende des Postings die ganzen Dateien auch als Zip-File zum Download an. Das RSS-Programm Vienna (Mac OS X) zeigt den Feed brav an, während NetNewsWire keine Postings laden will. Sobald ich darauf eine Antwort habe, wird das aber seperat behandelt. Ich denke aber das der Code so aber schon einmal ein gutes Fundament für unser späteres AddOn bieten wird.

Fangen wir an - Anlegen von mySQL-Tabellen

Überlegen wir zunächst, wie das ganze in unserem xt:Commerce Shop arbeiten soll. Sobald wir einen Artikel neu abspeichern wollen wir, dass ein neuer Eintrag in einer separaten mySQL-Tabelle abgespeichert wird, in diesem Fall wollen wir vorerst wenige Daten abspeichern. Wir benötigen für unseren RSS-Feed folgende Felder:

  • id
  • title
  • description
  • link

Während die ID nur eine fortlaufende Zahl ist, für welches sich nur mySQL interessiert, sollen in den anderen 3 Feldern jene Informationen gespeichert werden, welche später im Feed ausgegeben werden sollen. Der Code um diese Tabelle z. B. in phpmyadmin anzulegen muss wie folgt lauten:


CREATE TABLE `products_rss` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL ,
`description` TEXT NOT NULL ,
`link` VARCHAR( 255 ) NOT NULL
) ENGINE = MYISAM

Theorie und Praxis im xt:Commerce Shop

Welche Dateien müssen wir nun bearbeiten? Halten wir uns einmal vor Augen, wann ein Artikel gespeichert wird. Im Admin-Bereich wird beim Anlegen von neuen Artikeln die categories.php geladen. Diese Datei untergliedert sich ebenfalls in mehrere Teilbereiche - Produkte anlegen, ändern löschen sowie Ordner anlegen, ändern und löschen. Da wird weitgehenst vom Original-Quellcode fernbleiben wollen, wird diese nur minimal bearbeitet. Zuerst erstellen wir uns eine neue Klasse für die RSS-Feeds. Eine Klasse hat den Vorteil das wir diese schnell skalieren und an neue Gegebenheiten anpassen können.

Wir erstellen uns zunächst unsere RSS-Klasse. Diese legen wir im Ordner /admin/includes/classes an. Wir benennen die Datei wie folgt: products_rss.php. In dieser Datei legen wir einige Dateien an, die am Ende unsere Datenbank mit Feed-Einträgen füllen soll. Fangen wir zunächst mit der Variablen-Deklaration und dem Konstruktor an.

Variablendeklaration und Konstruktur


<?php
class product_rss {

	var $products_id;
	var $title;
	var $description;
	var $suchbegriffe;
	var $inhalt_final;
	var $picture;
	var $metadescription;
	var $productlink;

	function product_rss($data) {
	$this->description = $data['products_description_2'];
	$this->suchbegriffe = explode(',',$data['products_keywords'][2]);

	if($data['products_meta_description'] != '') {
		$this->metadescription = $data['products_meta_description'][2];
	}

	if($data['products_id'] == '') {
		$this->products_id = $this->getNewID();
	}

	$this->link = HTTP_SERVER.DIR_WS_CATALOG.'product_info.php?info=p'.$this->products_id.'.html';

		return true;
	}

Erklärung der Variablendeklaration und des Konstruktors

Wir legen zunächst einige Variablen an, die uns später helfen sollen unseren Feed-Beitrag zu gestalten. Dazu benötigen wir die neue Produkt-ID für den Link, sowie den Titel - also den Produktnamen und die Beschreibung. Ferner möchte ich einbauen, dass man im Feed ebenfalls Links angezeigt bekommt in der die xt:Commerce Suche benutzt wird. Desweiteren benötigen wir kleinere Hilfsvariablen wie $inhalt_final. In dieser Variable wird der fertige Feed-Eintrag gespeichert. Die Metadescription des Artikels benutzen wir als Untertitel für den Feed-Titel. Das hat zwei Vorteile:

a) Im Feed selber wird etwas mehr ausgegeben, evtl. sogar etwas Interessantes was zum kaufen animiert
b) Wir sind fleißig und füllen wie es sein sollte alle Felder aus

Über den Produktlink können wir dann über den Feed-Eintrag direkt auf die Produktseite wechseln. Nun kommen wir zu dem Konstruktor, also die erste Funktion die die Klasse aufruft. In dieser Klasse werden alle POST-Variablen welche im Eingabedialog eingegeben wurden verarbeitet. Nicht alle aber immerhin ein Teil. Besondere Beachtung sollte man der Zeile $this->products_id = $this->getNewID(); widmen. Da der Post an dieser Stelle noch nicht in der Datenbank vorhanden ist, müssen wir mit einer kleinen Hilfsfunktion die neue ID herausfiltern. Dazu basteln wir uns folgendes Gebilde:


	function getNewID() {
			$new_pid_query = xtc_db_query("SHOW TABLE STATUS LIKE '".TABLE_PRODUCTS."'");
			$new_pid_query_values = xtc_db_fetch_array($new_pid_query);
			$pid = $new_pid_query_values['Auto_increment'];

			return $pid;
	}

Hinzufügen des Produktbildes und Erstellen des Beitrags

Da wir später in unserem xt:Commerce RSS Feed auch das Produktbild anzeigen möchte, müsen wir sicherstellen das wir es auch aus der Datenbank laden. Dazu benutzen wir eine Funktion um die Datenbank abzufragen:


	function getProductImage() {
	$sql = "SELECT products_image FROM ".TABLE_PRODUCTS." WHERE products_id='".$this->products_id."'";
	$imagedb = xtc_db_query($sql);
	$image = xtc_db_fetch_array($imagedb);
	return $image['products_image'];
	}

Nun erstellen wir uns eine Funktion welche die in der Klasse befindlichen Daten in einen kleinen HTML-Block packt, damit diese später aus der Datenbank ausgelesen werden können. Ich habe folgende Anforderung an die Datei:

- Die Datei soll auf jede Variante reagieren können

Das heißt die Funktion soll sowohl beim Anlegen eines neuen Artikels, sowie auch beim Löschen eines Artikels reagieren und des rss-Feed füllen. Effektiv bedeutet das, dass wir mit einer switch-case-Schleife arbeiten sollten um alle Varianten durchzuprüfen. Die vorläufe Funktion wird folgendermaßen aussehen:


function create_feeditem($type) {

	switch($type) {
		case 'new_product' : {
			$this->title = 'Neuer Artikel im Shop: '.$data['products_name'][2];
			$this->picture = $this->getProductImage();

			$back = '';
			$back .= "<h1>$this->title</h1><br />";

			if($this->metadescription != '') {
				$back .= $this->metadescription."<br />";
			}
			$back .= "<table><tr><td><img src=\"".HTTP_SERVER.DIR_WS_CATALOG_INFO_IMAGES.$this->picture."\"/></td><td>$this->description</td></tr>";
			$back .= '<tr><td colspan="2">';
			$back .= "<h3>Den Artikel findet man unter folgenden Suchbegriffen: <br /><ul>";
			foreach($this->suchbegriffe as $term) {
				$back .= '<li><a href="'.HTTP_SERVER.DIR_WS_CATALOG.'advanced_search_result.php?keywords='.trim($term).'&amp;amp;amp;amp;x=0&amp;amp;amp;amp;y=0&phpMyAdmin=fac4b407329t262ea922">'.$term.'</a></li>';
			}
			$back .= '</ul></td></tr></table>';
			break;
		}
	}

	return $back;
	}

Zwei weitere Hilfsfunktionen

Das einzige was wir jetzt noch in der Klasse benötigen sind zwei Funktionen. Eine, die angib dass wir einen neuen Artikel in den Feed schreiben möchten und eine die die Daten in die Datenbank abspeichert. Diese zwei sind relativ leicht und schnell abgehandelt:


	function create_new_product_rss() {
	$this->inhalt_final = $this->create_feeditem('new_product');
	}

	function insert_rss() {
		$query = xtc_db_query("INSERT INTO products_rss (title, description, link) VALUES ('".$this->title."','".$this->inhalt_final."','".$this->link."')");
		return true;
	}
}
?>

Der Code noch einmal komplett


<?php
class product_rss {

	var $products_id;
	var $title;
	var $description;
	var $suchbegriffe;
	var $inhalt_final;
	var $picture;
	var $metadescription;
	var $productlink;

	function product_rss($data) {
	$this->description = $data['products_description_2'];
	$this->suchbegriffe = explode(',',$data['products_keywords'][2]);

	if($data['products_meta_description'] != '') {
		$this->metadescription = $data['products_meta_description'][2];
	}

	if($data['products_id'] == '') {
		$this->products_id = $this->getNewID();
	}

	$this->link = HTTP_SERVER.DIR_WS_CATALOG.'product_info.php?info=p'.$this->products_id.'.html';

		return true;
	}

	function getNewID() {
			$new_pid_query = xtc_db_query("SHOW TABLE STATUS LIKE '".TABLE_PRODUCTS."'");
			$new_pid_query_values = xtc_db_fetch_array($new_pid_query);
			$pid = $new_pid_query_values['Auto_increment'];

			return $pid;
	}

	function getProductImage() {
	$sql = "SELECT products_image FROM ".TABLE_PRODUCTS." WHERE products_id='".$this->products_id."'";
	$imagedb = xtc_db_query($sql);
	$image = xtc_db_fetch_array($imagedb);
	return $image['products_image'];
	}

	function create_feeditem($type) {

	switch($type) {
		case 'new_product' : {
			$this->title = 'Neuer Artikel im Shop: '.$data['products_name'][2];
			$this->picture = $this->getProductImage();

			$back = '';
			$back .= "<h1>$this->title</h1><br />";

			if($this->metadescription != '') {
				$back .= $this->metadescription."<br />";
			}
			$back .= "<table><tr><td><img src=\"".HTTP_SERVER.DIR_WS_CATALOG_INFO_IMAGES.$this->picture."\"/></td><td>$this->description</td></tr>";
			$back .= '<tr><td colspan="2">';
			$back .= "<h3>Den Artikel findet man unter folgenden Suchbegriffen: <br /><ul>";
			foreach($this->suchbegriffe as $term) {
				$back .= '<li><a href="'.HTTP_SERVER.DIR_WS_CATALOG.'advanced_search_result.php?keywords='.trim($term).'&x=0&y=0&phpMyAdmin=fac4b407329t262ea922">'.$term.'</a></li>';
			}
			$back .= '</ul></td></tr></table>';
			break;
		}
	}

	return $back;
	}

	function create_new_product_rss() {
	$this->inhalt_final = $this->create_feeditem('new_product');
	}

	function insert_rss() {
		$query = xtc_db_query("INSERT INTO products_rss (title, description, link) VALUES ('".$this->title."','".$this->inhalt_final."','".$this->link."')");
		return true;
	}
}
?>

Das Ganze in die categories.php einbauen

Nun müssen wir das ganze vorerst einmal einbauen, damit neue Artikel auch gespeichert werden. Hierzu öffnen wir wie bereits gesagt die categories.php aus dem admin-Ordner. Zuerst suchen wir uns die Zeile heraus, in der der Fall behandelt wird, wenn ein neues Produkt eingefügt wird (insert_product -> ca. Zeile 140). Hier wird der betreffende Teil folgendermaßen abgeändert:

case 'insert_product' :

$rss = new product_rss($_POST);
$catfunc->insert_product($_POST, $current_category_id);
$rss->create_new_product_rss();
$rss->insert_rss();

break;

Mehr braucht es auch vorerst in dieser Datei nicht. Ein Backup im Voraus macht aber trotzdem Sinn.

Einen Feed für xt:Commerce generieren

Was ist wohl das auffälligste an einem Feed-Link, sagen wir z. B. in WordPress? Ein Link sieht in den meisten Fällen folgendermaßen aus: http://www.domain.de/feed
Dieses Gebilde können wir ganz einfach realisieren. Wir erstellen auf unserer xt:Commerce - Root einen Ordner "feed" in der wir lediglich eine index.php abspeichern, welche folgenden Inhalt hat


<?php
echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
?>
<rss version="2.0">
 <channel>
	<title>Neue Produkte bei Testshop</title>
   <link>http://localhost:8888/xtcommerce</link>
   <description>Unsere Artikel im Überblick  </description>
 <?php
  define('DB_SERVER', 'localhost'); // eg, localhost - should not be empty for productive servers
  define('DB_SERVER_USERNAME', 'root');
  define('DB_SERVER_PASSWORD', 'root');
  define('DB_DATABASE', 'xtcommerce');

	 $connection = mysql_connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD) or
	 die('Connection to the specified database couldnt be established');
	 mysql_select_db(DB_DATABASE)  or
	 die ('Specified database couldnt be selected');  

	 $query = "SELECT * FROM products_rss ORDER BY id DESC";
	 $result = mysql_query($query) or die ("Query couldn't be executed");  

	 while ($row = mysql_fetch_array($result)) {
		print "<item>
			 	<title>".$row['title']."</title>
		 		<link>".$row['link']."</link>
		 		<description>".strip_tags($row['description'])."</description>
		 		<content:encoded><![CDATA[".$row['description']."]]></content:encoded>

</item>\n";
	 }
 ?>
 </channel>
 </rss>

Erklärung des Feed-Generators

In dieser Datei erstellen wir zunächst einen Header der angibt, dass es eine xml-Datei werden soll welche ausgegeben wird.
Danach erstellen wir zunächst einige Standardeinträge die in einer Feed-Datei vorhanden sein sollen. Danach fängt der eigentliche Zauber an. Wir definieren zunächst noch einmal unsere Datenbank-Konfiguration und bauen eine Verbindung zu unserer xt:Commerce Datenbank auf. Danach wählen wir alle Einträge aus unserer angelegten Tabelle an, welche wir nach der ID sortieren lassen. Danach verarbeiten wir lediglich wie in anderen Skripts auch die Ausgabe. Mehr ist es auch an dieser Stelle vorerst nicht.

Abschließendes

Wie ich bereits eingangs erwähnt habe, wird es noch etwas dauern bis dieses Skript Serienreife erlangt und sollte demnach NICHT - ich wiederhole - NICHT auf Produktivservern eingesetzt werden. Es soll bis jetzt lediglich einen Überblick über die Technik und den damit verbundenden Methoden geben wie RSS arbeitet und wie man das selber in den eigenen GPL-Shop xt:Commerce einbauen kann. Das Skript wird in den nächsten Wochen immer erweitert - es lohnt sich am Ball zu bleiben. Viel Spaß beim selber testen. Wer Anmerkungen oder Verbesserungsvorschläge hat, kann diese gerne in den Kommentaren hinterlassen.

Download des xt:Commerce Moduls

xt:Commerce RSS Modul by seo-geek.de (801)

Weiterführende Links

Lade Dir diesen Post als pdf-Datei herunter: Wir bauen uns ein eigenes RSS-Modul für xt:Commerce (872)

Alle Posts der Woche 44 / 2009 anschauen

Fandest Du den Beitrag interessant?

Der Beitrag ist mir etwas wert:
Fatal error: Call to undefined function the_flattr_permalink() in /var/www/html/web1028/html/seo-geek-de/wp-content/themes/seogeek/single.php on line 48