Wie gut, dass nicht immer alles auf Anhieb funktioniert. Denn dann probiert man “es” halt igendwie anders - Und findet dabei manchmal Lösungen zu ganz anderen Problemen. Die Idee diesmal: Ein wirklich lockeres Verfahren, mit dem man das “&”-Problem in den xt:Commerce-Links lösen und somit für “valide Links” sorgen kann.

 

“Vorgeschichte” - Smart enough?

Lassen wir das mal unbeantwortet. Zumindest hat sich eine “intensive Runde Bedienungsanleitung” in Sachen “Smarty” zaunpfahlwinkend (ja fast schon “-fuchtelnd”) angekündigt. Denn ursprünglich wollte ich mich mal daran versuchen, ein paar “Modifier” für Smarty schreiben.

Was “Modifier” sind und wozu genau ich sie gerne einsetzen würde, dazu später mehr. Spätestens dann, wenn ich meine ersten eigenen PlugIns zum Laufen gebracht habe …

Wie dem auch sei: Weil’s nicht geklappt hat, “eigene” PlugIns / Modifier / Filter zu “installieren”, wollte ich mal ja mal ein bisschen an den bereits “laufenden” Erweiterungen herumspielen. Gesucht war als geeigneter “Testkandidat” ein PlugIn, das auch mit Sicherheit auf jeder Shop-Seite ausgeführt wird.

UPDATE: Inzwischen laufen die eigenen Modifier :-)
Und die » “Anleitung” dazu ist ebenfalls fertig.

 

Zentrale Sammelstelle - “Auspuff-Filter-Not”:

Im “plugins”-Ordner von Smarty wird man fündig, bei xt:Commerce 3.04 SP2.1 liegt der im Ordner “includes/classes/Smarty_2.6.14″.

Dort ist mit der Datei “outputfilter.note.php” ein PlugIn installiert, das im Grunde genommen nichts anderes macht, als sich den kompletten Shop-Inhalt zu greifen - und ein paar freundliche Hinweise* (in einer übrigens völlig überflüssigen Tabelle) drunter zu setzen.

Und genau das macht es auf jeder Shop-Seite. Schön ist vor allem, dass die gesamte HTML-Ausgabe des Shops in einer einzigen Variablen zusammengefasst ist. Und so kann man zentral alle Links in xt:Commerce “valide” machen - in dem man die in den Adressen enthaltenen "&" in "&" umwandelt.

*Um welche Hinweise es sich dabei handelt, werde ich hier nicht hinschreiben, die meisten “Intensiv-Nutzer” wissen vermutlich ohnehin bescheid. Und ansonsten wäre das die Antwort auf eine Frage, die im xtc-Forum konsequent ignoriert wird. *HandvornMundhalt*

 

Lösung - “Valide Links”:

Man muss also die Variable $tpl_output auf alle Inhalte von href= innerhalb von <a> sowie auf alle Inhalte von action= innerhalb von <form> durchsuchen - und in den Fundstellen alle & durch &amp; austauschen.

Mein Vorschlag dafür: Vor der letzten Anweisung, in der alles “zurückgegeben wird” - das ist die Zeile return $tpl_output.$cop; - in der Datei “outputfilter.note.php” einfach Folgendes einfügen:


function NoEntities($Input) {
	$TransTable1 = get_html_translation_table (HTML_ENTITIES);
	foreach($TransTable1 as $ASCII => $Entity) {
		$TransTable2[$ASCII] = '&#'.ord($ASCII).';';
	}
	$TransTable1 = array_flip ($TransTable1);
	$TransTable2 = array_flip ($TransTable2);
	return strtr (strtr ($Input, $TransTable1), $TransTable2);
}
function AmpReplace($Treffer) {
	return $Treffer[1].htmlentities(NoEntities($Treffer[2])).$Treffer[3];
}
$tpl_output = preg_replace_callback("/(<a[^>]*href=\"|<form[^>]*action=\")(.*)(\"[^<]*>)/Usi","AmpReplace",$tpl_output);
$tpl_output = preg_replace_callback("/(<a[^>]*href='|<form[^>]*action=')(.*)('[^<]*>)/Usi","AmpReplace",$tpl_output);
	

Damit wird der gesamte Shop “so gelassen wie er ist” - und die Link-Adressen erst direkt vor der HTML-Ausgabe korrigiert. Sollte es Probleme oder falsche Verlinkungen geben, müsste lediglich der “Original-Outputfilter” wiederhergestellt werden. Sicherheitskopie also nicht vergessen.

 

Anmerkungen:

1) AmpReplace: Sicher gibt es eine elegantere Möglichkeit zum Austausch der &, aber ich bin vorsichtshalber erst einmal den Weg gegangen, zunächst alle auftauchenden Entitities in “normale” Zeichen zurückzuwandeln - und über dieses Ergebnis einfach den Befehl “htmlentites” drüberlaufen zu lassen, um nicht versehentlich bereits “korrekte” Links (z.B. bei manchen Bannern) zu verfälschen.

Wer dazu eine schickere Idee hat - Bitte einfach melden! An einem regulären Ausdruck, der ausschließlich “alleinstehende” & findet, bin ich gescheitert … Der Umweg über “NoEntities” schien mir jedenfalls am sichersten.

2) Suchfunktion: Die Such-Anweisung preg_replace_callback(); wird in zwei verschiedenen Varianten ausgeführt, damit sowohl Links mit Double- als auch mit Singelqoutes “erwischt” werden. Zuerst hatte ich eine Version, die Beides gefunden hat. Aber da es auch JavaScript-Popups gibt, bei denen innerhalb von href=" … " Konstruktionen mit Singleqoutes auftauchen, wurde in diesen Fällen nur der Bereich vor dem PopUp-Befehl gefunden und “korrigiert”.

Um mit nur einmal preg_replace auskommen zu können, hätte also ein Teil des Suchergebnisses bereits in das Ende des Suchmusters eingebracht werden müssen - Ob das mit preg_replace überhaupt möglich ist, weiß ich nicht - mit “Backreferences” hat’s jedenfalls nicht geklappt … Auch hierfür sind andere Ideen willkommen.

 

Fazit:

Wer dem sportlichen Ehrgeiz “valid XHTML” verfallen ist, der kann das für die Links und Formular-Actions bei xt:Commerce über Smarty ein ganzes Stückchen einfacher hinkriegen, als ich es vor einiger Zeit in diesem Beitrag beschrieben habe.

Andere Lösungen: Für “valide Links” werden an verschiedenen Stellen auch “Patches” angeboten, zum Beispiel zusammen mit “YAML für xt:Commerce” - Das in diesem Template mitgelieferte “Patch” besteht aus mehreren entsprechend angepassten System-Dateien, mit denen die entsprechenden Originale ausgetauscht werden müssen.

Smarty oder Patch? Ich würde sagen “Geschmacksache”. Prinzipiell ist es schon sauberer, das “Übel an der Wurzel zu packen” - und von Anfang an für “valide Links” zu sorgen. Nur im Hinblick auf Upgrades (die SP 2.2 kommt ja bald) bin ich dafür, Änderungen am System weitestgehend zu vermeiden. Und die “Smarty-Outputfilter” befinden sich zwar im System-Ordner von xt:Commerce, die meisten von ihnen beeinflussen aber letztendlich nur den ausgegebenen HTML-Quelltext und haben keine weiteren Auswirkungen.

Geschwindigkeit? Mit der hier vorgestellten Methode wird natürlich ein beträchtlicher Haufen von Buchstaben durchkämmt - und Shop-Seiten sind lang. Aber Smarty verfügt über ein effizientes und sehr schnelles Caching-System. Und wenn man die “Durchsuchung” weit genug “vorne” durchführt, werden bearbeitete Ergebnisse im Cache gespeichert und nicht im Cache gespeicherte Ergebnisse bearbeitet, so dass die Performance eigentlich nicht merklich leiden dürfte.

 

Warum valide Links?

Allgemein sind “valide Links” nicht nur meiner Meinung nach nicht unbedingt unerlässlich - und die teilweise kritischen Meinungen kann ich gut nachvollziehen.

Nichtsdestotrotz: Mir persönlich helfen “valide Links” vor allem beim Erstellen von xt:Commerce-Templates. Denn insbesondere CSS basierte Layouts reagieren sehr empfindlich auf Fehler im Quelltext. Und ich persönlich finde “vergessene Tags” und ähnliches mit einem Klick auf einen der gängigen Online-Validatoren sehr viel schneller als durch “eigene Suche” oder “Quelltext kopieren und in den Web-Editor einfügen”.

Wenn man dann aber lauter Fehlermeldungen durch “falsch konstruierte Links” bekommt, kann man mit dem Validator-Ergebnis einfach nichts anfangen, weil durch die entstehenden Folgefehler quasi alles ab dem ersten Link als “Fehler” bemängelt wird.

 

Nachtrag: Verbessertes Suchmuster

Einige PopUp-Funktionen von xt:Commerce werden nicht mit Links konstruiert, so dass man mit “normalen Links” und “Formular-Actions” noch nicht alles abgedeckt hat.

Ein Beispiel dafür ist {$PRODUCTS_PRINT} in der Vorlage für Produkt-Details. Damit auch solche JavaScript-PopUps gefunden und korrigiert werden, hier ein Code-Vorschlag, bei dem sich die Suche nicht mehr auf Links und Formulare beschränkt, sondern gleich ein bisschen anders vorgeht.

Gesucht werden alle Zeichenketten …

  • … die mit http:// oder https:// beginnen
  • … und denen entweder ein " oder ein ' direkt vorangeht
  • … und denen entweder direkt ein " oder ein ' direkt folgt
  • … und die innerhalb von < und > auftauchen

Hier mein neuer Code-Vorschlag dazu:


function NoEntities($Input) {
	$TransTable1 = get_html_translation_table (HTML_ENTITIES);
	foreach($TransTable1 as $ASCII => $Entity) {
		$TransTable2[$ASCII] = '&#'.ord($ASCII).';';
	}
	$TransTable1 = array_flip ($TransTable1);
	$TransTable2 = array_flip ($TransTable2);
	return strtr (strtr ($Input, $TransTable1), $TransTable2);
}
function AmpReplace($Treffer) {
	return $Treffer[1].htmlentities(NoEntities($Treffer[2])).$Treffer[3];
}
$tpl_output = preg_replace_callback("/(<[^>]*['\"])(http[s]?\:\/\/[^'\"]*)(['\"][^<]*>)/Usi","AmpReplace",$tpl_output);
	

Auf diese Weise muss der Quelltext auch nur noch einmal durchsucht werden … An dieser Stelle übrigens vielen Dank an Katrin für den Hinweis.

 

 

Die in diesem Beitrag beschriebene Änderung ist mit xt:Commerce 3.04 SP2.1 getestet. Einige Testbestellungen habe ich mit einem entsprechend bearbeiteten System durchgeführt und selbst noch keine Fehlfunktionen entdeckt. Das muss natürlich nicht in jeder Konfiguration so sein. Sollten Ihnen Fehler auffallen, bitte ich um Benachrichtigung.

Bitte beachten Sie auch unbedingt die allgemeinen Hinweise zur Verwendung hier veröffentlichter Code-Beispiele - Und wie immer die Empfehlung, solche Eingriffe nicht sofort an Ihrem “Live-Shop” vorzunehmen!