Probleme des Gantry 5 mit den Joomla-Content-Tools

Obwohl das Gantry 5 ein ganz hervorragendes Template-Framework ist, hat es doch (noch) einige kleine Nachteile, die einen z.T. konzeptionelle Schwachstelle offenbaren - nämlich, dass es eine Template mit eigener Engine ist, die viele Dinge an Joomla vorbei erledigt. Eines der größten Probleme bereitet, dass Inhalte nicht mehr in der Datenbank abgelegt werden und auch nicht mehr durch die Joomla-Strukturen verwaltet werden, sondern leider vom Template in Dateien abgelegt werden. Zwei große Nachteil die sich hierbei für mich bereits offenbarten:

  • Die Joomla-Suchfunktionen/Search-Plugins greifen für diese Inhalte nicht. Wer also viele Inhalt darüber verwaltet, sollte sich dessen bewußt sein.
  • Fast alle bereitgestellten Particle unterstützen nicht die Joomla-Content-Plugins. Das macht sich z.B. bemerkbar wenn Sie Inhalte mit E-Mail-Adressen über Particles veröffentlichen. Diese E-Mail-Adressen werden nicht durch das E-Mail-Cloaking von Joomla erfasst, also nicht vor Spammer-Spidern geschützt. Leider macht dies nicht einmal das bekannte Contact-Particle - was wirklich eine unhaltbarer Zustand ist.
  • Auch gibt es Problem mit der Übersetzung von Particle-Inhalten z.B. über die Erweiterung FaLang. FaLang ist nicht darauf ausgelegt sich die zu übersetzenden Inhalte aus den Particle-Dateien zu holen.

Den o.g. Sachverhalten sollte man sich bewusst sein, wenn man Gantry-5-Templates einsetzt. Zumindest zu dem Problem mit dem fehlenden E-Mail-Cloaking im speziellen und der Anwendung von Content-Plugins auf Particle-Inhalte im allgemeinen, möchte ich hier eine praktikable Lösung anbieten, die micht viel Schweiß bis zur erfolgreichen Erkenntnis gegkostet hat.

 

Eine Lösung für das fehlende E-Mail-Cloaking in Gantry-5-Templates

 

{% extends '@nucleus/partials/particle.html.twig' %}

{% block particle %}

	{% if particle.title %}<h2 class="g-title">{{ particle.title|raw }}</h2>{% endif %}

	<div class="g-contact {{ particle.class|e }}">
		{% for contactitem in particle.contactitems %}
		    <div class="g-contact-item">
		        {% if contactitem.icon %}<div class="g-contact-icon"><span class="{{ contactitem.icon }}"></span></div>{% endif %}
		        {% if contactitem.label %}<div class="g-contact-label">{{ contactitem.label|raw }}</div>{% endif %}
		        {% if contactitem.label == 'E-Mail' %}
				{% if contactitem.text %}
					<div class="g-contact-text">
					{# joomla.call('JUri::root') - funktioniert so #}
					{{ joomla.html('email.cloak', contactitem.text)|raw }}{# nur Cloaking-Plugin anwenden #}
					{# gantry.platform.filter(contactitem.text)|raw #}{# Alle Joomla-Content-Plugins anwenden #}
					</div>{% endif %}
				{% else %}
					{% if contactitem.text %}<div class="g-contact-text">{{ contactitem.text|raw }}</div>{% endif %}
				{% endif %}
		    </div>
		{% endfor %}      
	</div>

{% endblock %}

 



Generelle Gantry5-Particle-Lösung für Grav und Wordpress

Die oben beschriebene Vorgehensweise ist perfekt geeignet für ein Cloaking innerhalb des CMS Joomla. Evtl. wissen Sie, dass Gantry5 ebenso als Template-Framework für das CMS GRAVity und auch für Wordpress nutzbar ist. Nur, oben angewendete Joomla-Methode email.cloak steht in den anderen CMS nicht zur Verfügung. Sicher kann man in Wordpress adäquate Methoden einsetzen, besser jedoch ist es eine allgemeingültige Methode zu entwickeln. Das ist besonders dann von Vorteil, wenn man als Entwickler z.B. ein Gantry5-Particle erstellt, welches für alle 3 CMS eingesetzt werden soll, ohne spezielle Anpassungen.

Mein erster Versuch oder Ansatz war, im Script ene if-else-Abfrage einzubauen und je unterschiedliche Scriptsequenzen für die unterschiedlichen CMS auszuführen. Leider scheiterte dies. Der Grund war, dass wenn z.B. Filter in einem CMS nicht zur Verfügung stehen, der TWIG-Parser mit einem Fehler reagiert auch wenn dieser Filter nur in einem "toten" else-Zweig liegt. Tatsächlich ist es so, dass in GRAV einige Filter mehr zur Verfügung stehen als in Joomla, z.B. für das Cloaking von Mails. Funktionen/Filter wie |ord oder |safe_email stehen in Joomla nicht zur Verfügung. In Joomla führt der Aufruf solcher Filter zu Error-Abbrüchen. Das wird vermutlich unter Wordpress ebenfalls so sein.

Fazit: Ich habe nach einer Lösung gesucht, die so kompatibel ist, dass diese indentisch genutzt in allen drei CMS funktioniert.

Die nachfolgenden Scriptzeilen lassen sich also in alle Particle einfügen, in denen Mail-Adressen veröffentlicht werden und diese laufen in Wordpress, Joomla und GRAVity "out of the box".

{% if row.linkvalue %}
	{#% if joomla %#}
	{# joomla.call('JUri::root') - funktioniert so #}
	{#% {{ joomla.html('email.cloak', row.linkvalue)|raw }}{# nur Cloaking-Plugin anwenden #}
	{# gantry.platform.filter(contactitem.text)|raw #}{# Alle Joomla-Content-Plugins anwenden #}

	{% import _self as self %}

	{% set Aet = '&#64;' %}
	{% set AdrArr = row.linkvalue|split('@') %}
	{% set mailToStrg = 'mailto' %}
	{% set AdrFirstPart = AdrArr[0] %}
	{% set AdrDomainPart = AdrArr[1] %}

	{% set Unique = [] %}
	{% set alpha = 'abcdefghijklmnopqrstuvwxyz' %}
	{% set numbers = '0123456789' %}
	{% for i in 1..20 %}
		{% set randomCharacter = random(alpha ~ alpha|upper ~ numbers) %}
		{% set Unique = Unique|merge([randomCharacter]) %}
	{% endfor %}
	{% set Unique = Unique|join %}

	<span id="cloak{{ Unique }}">Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein!</span>
	<script type='text/javascript'>
		document.getElementById('cloak{{ Unique }}').innerHTML = '';
		var prefix = '{{ self.ordno(mailToStrg) }}';
		var aet = '{{ Aet|raw }}';
		var attrib = 'hr' + 'ef' + '=';
		var addy{{ Unique }} = '{{ self.ordno(AdrFirstPart) }}';
		addy{{ Unique }} = addy{{ Unique }} + aet + '{{ self.ordno(AdrDomainPart) }}';
		var addy_text{{ Unique }} = '{{ self.ordno(AdrFirstPart) }}' + aet + '{{ self.ordno(AdrDomainPart) }}';
		document.getElementById('cloak{{ Unique }}').innerHTML += '<a ' + attrib + '"' + prefix + ':' + addy{{ Unique }} + '">' + addy_text{{ Unique }} + '</a>';
	</script>
{% endif %}

Oben sichtbares Script ist die Sequenz die im Wesentlichen ein JavaScript erzeugt, welches die Mail-Adresse, die hier in row.linkvalue übergeben wird verschlüsselt. Dabei werden Teile der Mail-Adresse in HTML-Code der &#000; umgewandelt und ausgegeben. Diese mehrfach auf Teile der Mail-Adresse einzeln angewendete Umwandlung wird über ein Twig-Macro gemacht, das im Twig-Script ganz oben definiert wird. Das Macro sieht wie folgt aus:

{% macro ordno(strg) %}{% spaceless %}
	{# https://www.w3schools.com/html/html_charset.asp #}
	{% set CharArr = {'!':33,'#':35,'$':36,'%':37,'&':38,'’':39,'*':42,'+':43,'-':45,'.':46,'/':47,'0':48,'1':49,'2':50,'3':51,'4':52,'5':53,'6':54,'7':55,'8':56,'9':57,'=':61,'?':63,'^':94,'_':95,'`':96,'a':97,'b':98,'c':99,'d':100,'e':101,'f':102,'g':103,'h':104,'i':105,'j':106,'k':107,'l':108,'m':109,'n':110,'o':111,'p':112,'q':113,'r':114,'s':115,'t':116,'u':117,'v':118,'w':119,'x':120,'y':121,'z':122,'{':123,'|':124,'}':125,'~':126} %}

	{% set strg = strg %}
	{% set out = '' %}
	{% for i in range(0, (strg|length) - 1) %}
		{% set charOrig = strg[i:1] %}
		{% set charLowr = charOrig|lower %}
		{% if random(01) %} {# Zufall 0 oder 1 #}
			{% set No = CharArr[charLowr] %}

			{% if charOrig in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' %}
				{% set No = No - 32  %}
			{% endif %}

			{% set out = out ~ '&#' ~ No ~ ';' %}{# das Xte Zeichen als ord() #}
		{% else %}
			{% set out = out ~ charOrig %} {# das Xte Zeichen normal #}
		{% endif %}
		{# return out|raw #}
	{% endfor %}
	{{ out|raw }}
{% endspaceless %}
{% endmacro %}