Kategorien
Allgemein Webentwicklung Werkzeuge

Webdriver und das Problem mit dem unsichtbaren Text.

Neulich stand ich vor einem Problem, in dem ich mittels PHP-Webdriver versuchte, portentiell versteckten Inhalt aus einer Seite auszulesen.

Leider ist es so, dass das ganze nicht funktioniert, wenn der Inhalt versteckt ist. Dann wird zwar das Element gefunden, wenn man $element->getText() nutzt, wird aber null bzw ein leerer String ausgegeben. Das ist natürlich unschön und Webdriver selbst hat auch keine Möglichkeit, das DOM selbst zu verändern.

Aber natürlich gibt es einen Weg, dafür zu sorgen, dass man die Inhalte auslesen kann, immerhin muss das Element einfach nur sichtbar sein. Aber was, wenn das Element selbst nicht unsichtbar ist, sondern ein Eltern-Element das verursacht?

Hier die mögliche Lösung

PHP-Webdriver hat die Möglichkeit, einen Javascript-Codeblock an den Browser zu senden (analog zu browser.execute), der zweite Parameter von executeScript wird als arguments[] an die JS-Funktion übergeben. Damit bekommen wir das zu untersuchende Element.

In einer While-Schleife geht es dann (wenn ein Element nicht sichtbar ist) Element für Element nach oben. Dabei bekommt jedes einzelne Element ein display: block !important gesetzt.

Sobald ein überordnetes Element sichtbar ist, sind wir fertig. Eine while-Schleife stellt hier eine einfache Möglichkeit dar, den DOM-Tree rekursiv hochzuwandern.

Es besteht dabei auch die Möglichkeit, ein Element aus diesem Codeblock, der in eine Lambda-Funktion (auch “anonyme Funktion”) gepackt wird, zurückzugeben und das Element in PHP weiterzuverarbeiten. Allerdings müsste das Element dann zwischen den beiden Umgebungen ständig das Element für meine Schleifen hin- und hergereicht werden, das ist vermutlich weniger performant, als das einmal am Stück durchzugehen und das komplett in Javascript durchzuziehen, ohne vorher zurückzuspringen.

    /**
     * @param Client $client
     * @param RemoteWebElement $element
     * @throws \Exception
     */
    private function makeElementTreeVisible($client, $element): void
    {
        if (!$element->isDisplayed()) {
            $response = $client->executeScript('
                var element = arguments[0];

                function isVisible(elem){
                    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length )
                    && window.getComputedStyle(elem).visibility !== "hidden";
                }

                while (!isVisible(element) ) {
                    element.setAttribute("style", "display: block !important")
                    element = element.parentNode;
                }
            ', [$element]);
        }
    }

Vermutlich nicht die super-perfomanteste Weise, aber zumindest sollten damit alle Edge Cases abgebildet sein.

Andere Möglichkeiten wären noch: den Style für alle Elemente setzen oder versuchen alle CSS-Styles zu entfernen (hilft halt nicht gegen Inline-Styles).

Habt ihr dieses Problem schon einmal gehabt? Wie habt ihr das gelöst?

Kategorien
Webentwicklung Werkzeuge

“To fix this issue you can simply rename your file to api2.php”

Ich bin ja auch Nutzer von InfiniteWP. Das ist eigentlich ein sehr gutes Tool zum Verwalten von mehreren WordPress-Instanzen.

Nun hatte ich in einem Kundenprojekt eine API entwickelt, die zur Authentifizierung ein WordPress mit einer Nutzerdatenbank verwendet. Dazu habe ich von einem externen Projekt die wp-load.php inkludiert. Das funktionierte auch eine zeitlang auch sehr gut, bis die Agentur, die die Seite betreut, ein paar Änderungen vornahm. Sie installierten unter anderem InfiniteWP. In der datei “api.php” von InfiniteWP ist folgender Code:

if(basename($_SERVER['SCRIPT_FILENAME']) == "api.php"):
    exit;
endif;

Das Ziel dieses Codes ist relativ offensichtlich: Die Datei sollte nicht direkt geladen werden können. Blöd ist: Es wird nur auf den Dateinamen geprüft. Da meine externe Datei, auch api.php heisst, wird aber, sobald ich die wp-load.php include, das exit; ausgeführt.

Ich regte also an, vielleicht nicht nur den Filename zu überprüfen, sondern vielleicht auch den Pfad des aufgerufenen Scripts oder – wie unter WP auch nicht unüblich – auf eine gesetzte Konstante. Auf meine Anfrage beim Support bekam ich folgende Antwort:

Thanks for taking the time to reach out to us on your query. Your patience is greatly appreciated.

We are using api.php in our client plugin to use call back functions for our addons.
To fix this issue you can simply rename your file to api2.php

Are you experiencing any conflict issues with IWP client plugin and other plugins?
Please give us more information so that I can assist you accordingly.

Ich habe dann etwas möglicherweise etwas unhöflich reagiert und gefragt, wie sich das verhält, wenn der nächste dann das gleiche mit proxy.php und jemand anderes dann die index.php seines Plugins so schützt. Und dass ein HTTP Status 200 und eine weiße Seite in dem Fall auch nicht sinnvoll debugbar sind und dass mich das einige Tage Projektverzögerung gekostet hat und ziemlich beschissen ist. Zumal es in WordPress ja auch Beispiele gibt, wie es besser geht.

Erst darauf hin habe ich die Antwort bekommen, dass ein “scope of improvement on our end” vorhanden sei. Da geben sich dann Codequalität und Servicequalität dann echt nichts.

Ich habe mal ein Beispiel geschickt, wie man das sinnvoller lösen kann. Mal sehen, wann ein Update dafür kommt.

Kategorien
Changelog Releases Webentwicklung Werkzeuge

Statischer Seitengenerator: Hugo

Ich bin ja Fan von Hugo, und versuche, viele Probleme mit einem Statischen Tool zu erschlagen, wenn es denn geht.

Im Fall von Hugo sind das in den letzten Versionen ein paar mehr Dinge mehr geworden, die man damit lösen kann.

  1. Multi-Language. Eine ziemlich durchdachte Geschichte, die man da gebaut hat.
  2. Neue Struktur. Alles ist eine Seite. Damit lassen sich auch Index-Seiten als ganz normale Seiten behandeln
  3. Neue Template-Möglichkeiten: block templates

Diese letzten beiden Releases haben gezeigt, dass Hugo einen deutlichen Innovationsvorsprung gegenüber Jekyll und teilweise sogar WordPress hat. Im Forum von Hugo findet man sehr viele hilfsbereite User und Entwickler, die teilweise auch mal eigene Ideen vorstellen, die man super adaptieren kann.

Beispiel gefällig? Das Tutorial mit dem “Simple JSON site index” eignet sich auch hervorragend als Grundlage für das erstellen einer JSON-API für Apps oder ähnliches.

Kategorien
Changelog Releases Webentwicklung Werkzeuge

pimcore 4.4.x

Ich hatte ja schon vor einer Weile mal Artikel zum Thema pimcore veröffentlicht. Damals habe ich, ganz besonders unter “Was ist pimcore und wofür brauche ich das?” an einigen Stellen kein gutes Haar gelassen.

Die Erfahrungen, die ich mit den frühen Versionen von pimcore gesammelt habe, was das Thema Anpassung des Datenmodells bei einer Weiterentwicklung eines Projekts in verschiedenen Entwicklungsstufen angeht, habe ich damals stark kritisiert.

Innerhalb dieser 1,5 Jahre seit Erscheinen des Artikels hat sich einiges verändert, eigentlich ziemlich konstant zum Guten hin.

Unter diesen Umständen habe ich pimcore neu evaluiert und bin zu dem Entschluss gekommen, dass das ganze durchaus eine neue Chance verdient hat und sicher bei dem einen oder anderen Projekt in Zukunft zum Einsatz kommen wird.

Kategorien
Webentwicklung

WordPress Premium Themes — Ein Fazit

Ich habe im letzten Monat für eine Immobilienfirma in Hamburg gearbeitet und dabei auf einem Theme aufgesetzt, welches der Kunde sich gewünscht hat. Ein WordPress-Premium-Theme.

Ich hatte in der Vergangenheit ein paar Projekte mit Themes von Elmastudio umgesetzt, was ich auch nie wirklich als problematisch empfand. Die Themes sind recht ausgereift und überschaubar.

Nun hatte ich einen Kunden, der eine Seite auf Basis eines amerikanischen Premium-Themes erstellt haben wollte. Die Vorleistung, die das Theme liefert, hätte ich in der kurzen Zeit nicht aufholen können. Allerdings weiss ich nach über 10 Jahren Softwareentwicklung, dass in jedem Projekt, in dem ein Framework zum Einsatz kommt (oder man selbst etwas einigermaßen Framework-ähnliches im Zuge dessen entwickelt).

Die Demo des Themes zeigt so einige Dinge, was dabei nicht erwähnt wird: 50% dieser Dinge, die auch beim Kunden die Kaufentscheidung stark beeinflusst hatten, werden von diversen kostenpflichtigen Premium-Plugins nachgeliefert, für die (und nur die) das Theme auch entsprechende Vorbereitungen mitbringt.

Basis des Themes bildet eine Integration von WP-Job-Manager. Soweit so gut. Damit diese Jobs in dem Theme auch facettiert gesucht werden können, muss WP-Facet-Search gekauft und installiert werden (79$). Damit die Jobs dann auch die Tags-Taxonomie von WordPress verwenden können, muss das entsprechende Plugin für 19$ gekauft werden. Slider Integration besteht für das Theme keine.

Um einen Slider auf der Homepage zu integrieren, musste ich ein neues Template erstellen und einige Styles anpassen, damit das überhaupt funktioniert hat.

Für die “widgetized Homepage” die Templates für die Widgets zu überschreiben wäre eigentlicht einfach, wenn man, wie sonst auch im Theme “get_template_part()” verwendet oder die Widget-Functions wenigstens pluggable gemacht hätte. So konnte ich komplette Funktionen inkl integiertem HTML kopieren und damit die Anzahl der Widgets fast verdoppeln.

Einfach war dann hingegen das Erweitern der Jobs-Einträge um neue Felder – das ist aber eher eine Funktion von WP Jobs Manager, nicht vom Theme.

Ach ja: Um mit WP-All-Import neue Einträge in die Datenbank mit den neuen Feldern (oder auch denen, die das Theme schon hinzugefügt hat) zu importieren, wäre auch noch ein Premium Plugin notwendig.

Und SVG-Icons inline mit get_template_part() einzubinden, finde ich wieder eine sehr gute Idee.

Und wenn ein Theme mit Customify kommt: nutzt für eigene Styles und Scripte lieber ein Child theme statt den Funktionen für “Custom CSS” und “Custom Javascript”. Das ist versionierbar, cache-freundlich und deutlich einfacher ausrollbar.

Fazit

Ich bin nicht begeistert von solchen Single-Purpose-Themes. Insbesondere nicht, wenn das Theme umfangreiche Extra-Funktionen mitbringt, die mit dem Wechsel des Themes verloren gehen. Da es in diesem Fall um Immobilien ging, wäre eine Lösung auf Basis von WpCasa vermutlich sinnvoller und nachhaltiger gewesen, da es mittlerweile auf einem (Free) Plugin basiert (auch hier sind kostenpflichtige Erweiterungen vorhanden). Bei einem Relaunch der Seite, die dann mit weniger Zeitdruck erfolgt, werde ich das auch noch mal genauer evaluieren.

Jedenfalls ist meine Erwartung, wenn ich ein solches Single-Purpose-Theme kaufe, dass das ganze wie in den Demos funktioniert und wenn ich dafür etwas nachkaufen muss, dann sollte das in der Demo auch dabeistehen, was noch zusätzlich für die Funktion gekauft werden muss. Für mich als Entwickler ist das nämlich ziemlich besch****, wenn ich alle Nase lang sagen muss “dazu musst Du noch Plugin xy für xx$ nachkaufen”. Mag sein, dass andere das anders machen, ich finde das unschön.

Lernen kann man von den Premium-Themes auf jeden Fall einiges, gutes, und schlechtes.