WordPress nahezu perfekt suchmaschinenoptimiert in xt:Commerce integrieren

Man kann mit dem integrierten Content Manager von xt:Commerce allerhand Sachen anfangen, jedoch fehlt eine Newsverwaltung. Das wollen wir heute ein wenig suchmaschinenoptimiert aufpolieren. Wir verbinden WordPress mit xt:Commerce so, dass man es nahezu nicht merkt, dass WordPress im Hintergrund läuft. Es wird so aussehen als ob das Shopsystem xt:Commerce diese News selber verarbeiten würde. Wir benutzen hierzu die mächtige Custom-Fields-Funktion von WordPress. Damit können wir alle wichtigen Daten für xt:Commerce aufbereiten.

Diese Woche werden wir eine Methode verwenden, die ohne WordPress-Funktionen auskommt - also nur mit SQL-Statements und selbstgestrickten PHP-Funktionen. Dies mache ich deshalb, da man diese Methode theoretisch auch auf andere Blogsysteme übertragen kann. Man muss lediglich wissen, wo in einer Datenbank die Daten liegen.

Gleich vorweg - die Modifikation kann zwar jeder durchführen, allerdings sollte man speziell wenn man wenig Erfahrung in der Programmierung hat mindestens 1 mal pro Tag und Änderung eine Sicherung der Daten machen, die man bearbeitet.

Vorbereitungen in WordPress

Wie bereits erwähnt benötigen wir in WordPress einige Custom Fields (Benutzerdefinierte Felder). Da wir unsere Blogeinträge suchmaschinenoptimiert anlegen möchten, benötigen wir hierzu einige Felder. Jeweils 3 Felder für die ausgegebenen Links und noch einmal 3 für seourl, seotitle (für den Title Tag des Links) und seoalt (der Vollständigkeit halber). Ebenso benötigen wir ein Custom Field für die Auswahl ob wir einen Weiterlesen-Link anzeigen möchten oder nicht. Das möchte ich einfügen, damit wir längere Beiträge auf einer seperaten xt:Commerce Seite anzeigen können - komplett mit Meta-Description, Meta-Tags und Title-Tag.

Wir benötigen also folgende Custom Fields in WordPress:

  • metadesc:
    Dieses Custom Field benötigen wir für eine einzeln angezeigte Artikel-Seite für die Meta-Descripton. Dies ist ein wichtiger Faktor für unsere Suchmaschinenoptimierung, da in vielen Suchmaschinen ein Teil der Description ausgegeben wird.
  • metatitle:
    Wie bereits in der Description benutzen wir hier dieses Feld für den Title-Tag
  • metatags:
    Auch wenn Meta-Tags mittlerweile eine verschwindend geringe Rolle für Suchmaschinenoptimierung spielen gehört es meiner Meinung nach immer noch zu gutem SEO und gutem HTML dazu.
  • seoalt:
    Dieses Feld benutzen wir zur zur Anzeige eines Alt-Tags wenn ein Besucher mit der Maus über einen unserer Links geht. Hier kann z. B. ein ergänzender Text zu einem Link hinzugefügt werden.
  • seotitle:
    Wir bereits der Alt-Tag wird hier ein Title-Tag für den Link angelegt.
  • seourl:
    Hier vergeben wir einen sprechenden Link für unseren Beitrag. Dieser wird im späteren Verlauf innerhalb von xt:Commerce als Liste von Beiträgen ausgegeben.
  • weiterlesen:
    Wer lange Texte schreibt wird schnell merken, dass die Seite sehr scroll-lastig wird. Mit diesem Custom Field wollen wir eine Funktion einbauen, die uns erlaubt im Falle eines zu langen Textes einen Weiterlesen-Link anzuzeigen.

Wer mag kann an dieser Stelle bereits einige Artikel vorbereiten, damit das spätere Testen etwas schneller geht. Man sollte darauf achten, dass stets alle Custom Fields ausgefüllt sind um maximalen SEO-Effekt zu erzielen.

Fangen wir mit xt:Commerce an

Um dynamische Content-Seiten in xt:Commerce anzulegen, müssen wir diese vorher in einem Editor unserer Wahl aufbereiten und in einer php-Datei speichern. Dies ist allerdings nur ein Teil der Miete. Wir müssen in einen Core-Dateien von xt:Commerce ebenfalls etwas hinzufügen. Wie bereits gesagt:

Um genau zu sein benötigen wir die metatags.php aus dem include/modules Ordner. Diese werden wir uns erst einmal sichern. Bearbeiten werden wir sie später noch.

Zunächst etwas Theorie

Da ich auch möchte, dass alle meinen Gedankengänge nachvollziehen können, möchte ich zunächst etwas auf die Theorie eingehen. Da wir alle Daten vorher in WordPress eingeben, möchten wir diese nun auch ausgeben. Alle Daten werden von WordPress in Tabellen der mySQL-Datenbank abgespeichert. Es liegt nun an uns gezielt diese Tabellen abzufragen und deren Daten aufzubereiten. Die Daten die wir benötigen liegen in folgenden Tabellen:

  • wp_posts:
    Hier werden alle Beiträge gespeichert die wir in WordPress eingeben. Im vorliegenden Fall interessieren wir uns allerdings nur für eine bestimmte Kategorie und bereits veröffentlichte Postings. Wir beachten also gezielt alle Felder deren post_status gleich „publish“ ist.
  • wp_postmeta:
    Hier werden alle Meta-Daten (Custom Fields) gespeichert, welche wir beim Eintragen eines Posting in WordPress eintragen

Anhand der Posts werden wir mit einer Schleife in PHP eine Liste aller bisher geschriebenen Posts ausgegeben. Anhand der ausgelesenen Meta-Daten bauen wir uns eine schöne, sprechende suchmaschinenfreundliche Link-Liste.

Wir beginnen mit der Ausgabedatei für xt:Commerce

Unsere Ausgabedatei besteht aus 5 Teilen:

  • Aufbauen der Datenbankverbindung
  • Ausgabe aller Einträge als Linkliste
  • Ausgabe eines einzelnen Posts
  • Ausgabe der letzten x Beiträge im Kurzformat
  • Anzeigen einer Navigation

Fangen wir mit den Grundvariablen und den Aufbau der Verbindung zur Datenbank an. Ich gehe erst einmal alle Abschnitte seperat durch. Am Ende folgt noch einmal das komplette Listing.

Der Sprung in das kalte Wasser von xt:Commerce

Zu allererst erstellen wir uns eine neue PHP-Datei welche später in unserem Shop integriert wird. Dazu benutzen wir entweder einen Texteditor oder eine IDE unserer Wahl. Ich selber bevorzuge Coda oder Komodo Edit. Zweiteres kann man kostenlos downloaden.

Beginnen wir zunächst mit dem Header der Datei sowie der Datenbank-Verbindung und eine kleine Hilfsfunktion für die Datumsausgabe. Die Funktion zur Datumsausgabe generiert uns aus dem WordPress-erstellten Datum ein normales Deutsches Datumsformat, also TT.MM.JJJJ.


<?php

/* Festlegen der benötigten Variablen */
$category = '0';
$host = 'localhost';
$user = 'user';
$dbpass = 'passwort';
$database = 'datenbank';

function datum($stamp)
{
	if($stamp != '')
		{
		$temp = substr($stamp,0,10);
		$array = explode('-',$temp);
		$temp = $array[2].'.'.$array[1].'.'.$array[0];
		}
	return $temp;
}

   ///////// Geben Sie hier die Datenbank Informationen ein /////

   $linkwp = mysql_connect($host,$user,$dbpass); // hier die Daten aus der wp-config.php eingeben um die Verbindung zur Datenbank herzustellen.
   @mysql_select_db($database, $linkwp) or die( "Unable to select database"); 

Was genau geschieht hier? Wir legen zunächst fest, welche Kategorie wir ausgeben möchten. Dazu benutzen wir die Kategorie-ID. Diese finden wir in unserer WordPress Installation im Admin-Bereich, wenn wir eine Kategorie anlegen. Wenn Sie nicht angezeigt wird, findet man diese bei Überfahren des Links zu bearbeiten in der Fußzeile. Hierzu werde ich noch ein kleines Screencasts mit kurzen Tipps und Tricks nachreichen, sobald wieder etwas mehr Zeit ist. In den darauf folgenden Zeilen geben wir stellvertretend für die ganze Datei unsere Zugangsdaten zur Tabelle ein, in der unsere WordPress Daten liegen.

Danach folgt eine kleine Hilfsfunktion, die uns das Datum aus der WordPress Datenbank in ein deutsches 0815-Datumsformat umwandelt. Die Funktion kann entweder geändert werden oder man lässt sie später im Quelltext weg. Hier kommt es dann immer auf die Anforderung an.

Zu guter letzt in diesem Teil erstellen wir eine Datenbank-Verbindung mit alter mySQL-Methode und überprüfen ob wir eine Verbindung überhaupt aufbauen können.

Zurück zum Skizzenblock

Bevor es weitergeht muss wieder etwas Theorie zu der ganzen Sache her. Was haben wir vor? Wir wollen ein Skript basteln, welches auf mehrere Faktoren reagiert

  • Wird eine normale Ausgabe angezeigt?
  • Soll ein einzelner Post angezeigt werden?
  • Sollen Weiterlesen-Links unterstützt werden?
  • Soll eine Art Mini-Sitemap angezeigt werden?

Aus diesen gegebenen Punkten erkennen wir schon, dass wir mehrere If-Statements verwenden werden. Ich verspreche Euch, es sieht alles komplizierter aus als es ist. Ich bin zwar auch kein Vollprofil was PHP angeht, aber ich versuche es einigermaßen verständlich zu erklären.

Wir erstellen unsere xt:Commerce-Wordpress Mini-Sitemap

Fangen wir zunächst mit der Mini-Wordpress-Sitemap in xt:Commerce an. Der Code der jetzt kommt wird ebenfalls wieder in mehrere Teile untergliedert. Der Ablauf wird folgendermaßen sein:

Wenn die GET-Variable "postmap" übergeben wurde, soll eine Liste aller Links samt unseren eingegebenen Daten in WordPress angezeigt werden. Die htaccess wird hierzu später noch editiert. Neben postmap müssen wir noch abfragen ob eine postid übergeben wurde, sollte beides nicht zutreffen wird die "normale" Ausgabe gerendert. Hört sich zwar furchtbar kompliziert an, aber wir machen das ganze Schritt-für-Schritt.

Im Fall einer postmap-Variable...

Sollte postmap übergeben worden sein, müssen wir aus der Datenbank Daten herausholen und diese verarbeiten und anschließend ausgeben. Der Code dazu sieht folgendermaßen aus:


 if($_GET['postmap'])
   {
	echo "&amp;amp;Uuml;bersicht aller Eintr&amp;amp;auml;ge";
	$query="SELECT ID, post_title from wp_posts WHERE post_category = '$category' AND post_status = 'publish' ORDER BY id DESC";
	$result=mysql_query($query, $linkwp);
	$anzahl = mysql_numrows(mysql_query($query, $linkwp));
	$num=mysql_numrows($result);
	$i = 0;
	while($i < $num)
	{
		echo '<div class="post_eintrag"><a href="http://www.webshop.com/news/'.mysql_result($result,$i,"ID").'_';
		echo get_meta(mysql_result($result,$i,"ID"),'seourl');
		echo '.html" title="'.get_meta(mysql_result($result,$i,"ID"),'seotitle').'" alt="'.get_meta(mysql_result($result,$i,"ID"),'seoalt').'">'.mysql_result($result,$i,"post_title").'</a></div>';
		$i++;
	}
   }
   else
   {

Ich habe den Block bewusst bis else gehen lassen, damit man gleich sieht das es hier noch weitergeht. Lasst uns aber zunächst hier einen Blick hinwerfen was hier geschieht. Wir bauen uns SQL-Statement zusammen, in welchem wir aus der wp_posts Tabelle die ID und den Titel eines Posts herausholen, welche in der oben festgelegten Kategorie sind und gleichzeitg auch veröffentlicht worden sind. Das ganze sortieren wir aufsteigend nach der ID. Neue zuerst, alte zum Schluss. Wer hier anders sortieren möchte, ändern DESC auf ASC ab.Danach müssen wir das Statement auch verarbeiten und schauen wieviele Einträge es genau gibt.

Anhand der Anzahl der Einträge lassen wir eine while-Schleife starten, welches uns die ganze Geschichte ausgibt. Solange unsere Zählvariable $i kleiner als die Anzahl der WordPress-Einträge ist, geben wir zeilenweise die Ergebnisse aus. Dazu öffnen wir wegen der einfacheren Gestaltung hinterher einen DIV. Da wir auf die Links klicken wollen müssen wir auch Links anlegen.

Da wir suchmaschinenoptimiert arbeiten wollen wir natürlich auch Fancy-Urls verwenden, welche wir ja vorher eingegeben haben. Wir legen uns einen Link auf einen nichtvorhanden Ordner (in diesem Fall "news") an und fügen da unsere URL hinzu. Die nötigen Daten (ID, seourl, seotitle usw) lesen wir mit der Funktion get_meta aus, welche wir uns im späteren Verlauf in der metatags.php anlegen werden, da wir diese dort ebenfalls benötigen werden. Zum Schluss erhöhen wir die Zählvariable um 1geben wir noch den Titel aus und schließen den DIV wieder.

Wir geben einzelne WordPress-Beiträge aus

Was ist wenn eine postid übergeben wird, also wenn jemand wirklich entweder auf Weiterlesen oder auf einen Link unserer Mini-Sitemap klickt? In diesem Fall werden wir auch diesmal Daten aus der Datenbank entnehmen, diese aufbereiten und im Browser ausgeben.


  if($_GET['postid'])
   	{
	 $query="SELECT post_title as titel, post_date_gmt as datum, post_content as content from wp_posts WHERE ID = '".$_GET['postid']."' LIMIT 1";
	// mit limit legen Sie fest, wieviel Beiträge maximal angezeigt werden sollen
    $result=mysql_fetch_array(mysql_query($query,$linkwp));

	echo '<div class="post_container">';
	echo '<div class="post_titel"><h1>'.$result['titel'].'</h1></div>';
    echo '<div class="post_date">';
    echo datum($result['datum']);
	echo '</div>';
	echo '	<div class="post_textcontainer">';
	echo '		<div class="post_text">'.$result['content'].'</div>';
	echo '</div></div>';
	}
else

Hier wird sichergestellt ob eine postid übergeben wurde. Ist dies der Fall laden wir uns aus der Datenbank die dazu passenden Datensätze bzw. den Datensatz aus. Prinzipiell benötigen wir nur post_title, post_date_gmt und post_content. Dies kann allerdings nach Belieben geändert werden. HIer sind nahezu keine Grenzen gesetzt. Wurden die Daten aus der Datenbank geladen liegt es an uns wie diese ausgegeben werden. ich empfehle für jedes Feld eine eigene Div-Klasse zu erstellen.

Wenn alles andere nicht geht...

Wenn jemand die normale Newsseite aufruft werden keine Variablen übergeben. Kein postmap und auch keine postid. Ist dies der Fall müssen wir diesmal etwas mehr aufarbeiten. Wir müssen jeden Beitrag anzeigen, auswerten ob ein Weiterlesen-link angezeigt werden soll oder nicht und aus Gründen der Userfreundlichkeit auch eine kleine Pagination einbauen. Hier erst einmal der Quellcode. Dieser sieht jetzt richtig komplex aus, aber auch das kriegen wir locker hin.


{
	if (isset($_GET['start']))
		{
		$a = $_GET['start'];
		$b = 6;
		}
	else
		{
		$a = 0;
		$b = 6;
		}

	$query2="SELECT ID, post_title, post_date_gmt, post_excerpt from wp_posts WHERE post_category = '$category' ORDER BY id DESC ";
    $query="SELECT ID, post_title, post_date_gmt, post_excerpt from wp_posts WHERE post_category = '$category' AND post_status = 'publish' ORDER BY id DESC LIMIT $a,$b "; 

	// mit limit legt man fest, wieviel Beiträge maximal angezeigt werden sollen
    $result=mysql_query($query);
	$anzahl = mysql_numrows(mysql_query($query2));

    $num=mysql_numrows($result);
    $i=0;
    while ($i < $num) {
	$weiterlesena = "SELECT meta_value as weiter FROM wp_postmeta WHERE post_id = '".mysql_result($result,$i,"ID")."' AND meta_key = 'weiterlesen' LIMIT 1";
	$weiterlesen = mysql_fetch_array(mysql_query($weiterlesena));

    $excerpt=mysql_result($result,$i,"post_excerpt");
	$title=mysql_result($result,$i,"post_title");
	$id = mysql_result($result,$i,"ID");
	$date = mysql_result($result,$i,"post_date_gmt");
    ?> 

	<div class="post_container">
		<div class="post_titel"><h1><?php echo $title; ?></h1></div>
		<div class="post_date"> <?php echo datum($date); ?> </div>
		<div class="post_textcontainer">
			<div class="post_text"><?php echo $excerpt; ?> </div>
			<div class="post_more"><?
			if ($weiterlesen['weiter']=='ja')
			{
			echo '<a href="http://www.webshop.com/news/'.$id).'_';
			echo get_meta($id,'seourl');
			echo '.html" title="'.get_meta($id,'seotitle').'" alt="'.get_meta($id,'seoalt').'">&amp;amp;raquo;&amp;amp;nbsp;weiter lesen&amp;amp;nbsp;&amp;amp;hellip;</a>';
			}
			else
			{
			echo '&amp;amp;nbsp;';
			}
			?>
		</div>
		</div>
	</div>

    <?
    ++$i;
    } ?>
		<div class="post_pagenav">
		<?
		if ($_GET['start'] == 0)
			{
			}
		else
			{
			// Link zu vorherigen Postings
			$z = $_GET['start']-6;
			echo '<a href="http://www.webshop.com/shop_content.php?coID=99&amp;amp;start='.$z.'">&amp;amp;laquo;&amp;amp;nbsp;zur&amp;amp;uuml;ckbl&amp;amp;auml;ttern</a> | ';
			}

		if ($_GET['start'] <= $anzahl -6 &amp;amp;&amp;amp; $_GET['start'] <= $num)
			{
			// weitere posts
			$z = $_GET['start']+6;
			echo '<a href="http://www.webshop.com/shop_content.php?coID=99&amp;amp;start='.$z.'">vorbl&amp;amp;auml;ttern&amp;amp;nbsp;&amp;amp;raquo;</a>';
			}
		else
			{

			}
		?>
	</div>
	<div class="post_sitemap">
		<a href="http://www.webshop.com/news/news-uebersicht.html">&amp;amp;Uuml;bersicht aller Beitr&amp;amp;auml;ge</a>
	</div>
	<?
  }
   }
?> 

Als erstes überprüfen wir, ob schon eine Startvariable (wenn z. B. schon die ersten 6 Beiträge angezeigt wurden) übergeben wurde. Ist dies der Fall sagen wir, dass SQL dann bei $a anfangen soll und $b weitere Beiträge anzeigen möchte. Wurde nichts übergeben fangen wir gemächlich bei Datensatz 0 an und kämpfen uns bis Datenbank Nummer 6 vor. Die Zahlen können hier ohne weiteres angepasst werden.

Nun erstellen wir 2 SQL-Abfragen. Die erste soll nur ein Hilfsstatement darstellen, welches wir für die Navigation benötigen. Mit dem zweiten Statement lesen wir die aktuell anzuzeigenden Posts aus, hierzu verwenden wir den post_excerpt - die Kurzfassungs des Postings. Wäre man in WordPress selber könnte man hierauf verzichten, da wir aber alles quasi von 0 anfangen zu programmieren verweden wir beide Felder, da wir ja auch eine Weiterlesen-Funktion einbauen wollen. Anschließend arbeitet unser Skript ein wenig mit den Daten und gibt diese abermals in einer while-Schleife aus.

In dieser Schleife prüfen wir zunächst ob ein Weiterlesen-Link angezeigt werden soll. Danach werten wir alle Daten aus und übertragen diese in seperate Variablen. Dies muss nicht sein, erhöht aber die Lesefreundlichkeit des Codes.

Um das designen der Newseinträge etwas zu vereinfachen legen wir uns auch hier wieder diverse Div-Container mit seperaten lassen an, damit das Design weitgehenst variable bleibt. Wir geben also unseren Titel, das Datum und den Excerpt aus. Danach fragen wir ab, ob die weiterlesen-Variable von WordPress mit "ja" definiert ist. Ist dies der Fall geben wir erneut unseren SEO-Link aus.

Zum Schluß benötigen wir noch eine kleine Navigation, damit man nicht 20 Beiträge auf einer Seite hat. Wir umschließen auch dies mit einem DIV-Container und geben je nach übergebenen Variablen Möglichkeiten zum Vor- und Zurückblättern aus. Um das ganze abzurunden geben wir noch einen Link zur Übersicht aus, welchen wir mit der htaccess anpassen werden

Anpassen der .htaccess

Damit unser SEO-Zauber auch wirkt müssen wir zu dem ganze Code auch noch unsere .htaccess anpassen. Ohne diese Modifikation gibt es keine suchmaschinenfreundliche URLs. Die htaccess muss um folgende Zeilen erweitert werden, wobei hier auch wieder die ID der coID an die eigenen Bedürfnisse angepasst werden muss:

## Newseintraege
RewriteRule ^news\/news-uebersicht.html?$ shop_content.php?coID=99&postmap=yes [NC]
RewriteRule ^news\/(.*)_(.*).html?$ shop_content.php?coID=99&postid=$1 [NC]
RewriteRule ^informationen\/(.*).html?$ shop_content.php?coID=$1[NC]

Anpassen der metatags.php

Wie bereits angekündigt muss man in der metatags.php (zu finden in includes/modules/metatags.php) eine kleine Hilfsfunktion einfügen. Das hat den Hintergrund, dass PHP-Funktionen nicht doppelt in den Speicher geladen werden dürfen. Ich weiß dass das ganze eleganter und sicherer geht, aber das Skript ist schon einige Tage alt. Ich nehme es mir aber zum Ziel, dieses Skript noch weiter in Richtung Suchmaschinenoptimierung zu drücken.

Die Funktion ist relativ einfach aufgebaut. Wir übergeben die ID des Posts aus der WordPress-Datenbank und sagen welches Custom-Field ausgelesen werden soll. Der Code hierzu sieht folgendermaßen aus:


function get_meta($id,$tag)
{
   $linkdb = mysql_connect("<server>","<user>","<passwort>"); // please set these values as in configuration.php or wp-config.php
   @mysql_select_db("<datenbank>",$linkdb) or die( "Unable to select database");
   $abfrage = "SELECT meta_value FROM wp_postmeta WHERE post_id='".$id."' AND meta_key='".$tag."' LIMIT 1";

   $tags = mysql_fetch_array(mysql_query($abfrage));

   mysql_close($linkdb);
   return $tags['meta_value'];
}

Das Ganze abrunden

Wäre es nicht super, wenn wir jetzt auch noch individuelle Meta-Daten für jeden Artikel haben? Wir haben Sie ja bereits angelegt. Jetzt ist es an der Zeit eine Artikelseite weitgehenst für die Suchmaschine zu optimieren. Hierzu müssen wir in den ganzen Gewusel aus if-Abfragen noch einen kleinen Part einbauen. Nach der Abfrage "if($_GET['coID']) { fügen wir hinterher direkt folgenden Code ein:


if($_GET['postid'])
			{
				// rufe metas von news auf

				?>
				<meta name="description" content="<?php echo get_meta($_GET['postid'],'metadesc'); ?>" />
				<meta name="keywords" content="<?php echo get_meta($_GET['postid'],'metatags'); ?>" />
				<title><?php echo get_meta($_GET['postid'],'metatitle');?></title>
				<?
			}
		else
			{

Abschließendes

Das war auch schon wieder unsere kleine Modifikation. Ich weiß dass man manche Stellen sauberer, besser und vor allem schneller bewältigen kann. Das Skript habe ich vor ca. einem dreiviertel Jahr gebastelt und dumm wie ich war nicht allzu sehr kommentiert. Wir werden aber in den kommenden Wochen das Skript erweitern. Auch würde mich freuen, wenn andere dieses Skript neu aufbauen und anderen zu Verfügung stellen. Es wäre bestimmt interessant was für Funktionen und Möglichkeiten dazukommen könnten.

Wie versprochen gibt es nochmal den kompletten Quelltext als Download (von der rssfeed.php) rssfeed_xtc.php (354)

Ich freue mich auf Eure Kommentare. Ich hoffe die Anleitung gefällt und hilft Euch ein wenig auf Eurem Pfad zur Suchmaschinenoptimierung.


Alle Posts der Woche 33 / 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