Ich entwickle ein WordPress-Theme mit einer Template-Engine. Ich möchte, dass mein Code so gut wie möglich mit der WP-Kernfunktionalität kompatibel ist.
Ein Kontext zuerst
Mein erstes Problem bestand darin, einen Weg zu finden, um die Vorlage ausgehend von einer WP-Abfrage aufzulösen . Ich habe dieses Problem mit einer meiner Bibliotheken, Brain \ Hierarchy, gelöst .
In Bezug auf get_template_part()
und andere Funktionen, die Teilfunktionen wie und ähnliche laden get_header()
, get_footer()
war es ziemlich einfach, Wrapper in Teilfunktionen der Template-Engine zu schreiben.
Das Thema
Mein Problem ist jetzt, wie man eine Kommentarvorlage lädt.
Die WordPress-Funktion comments_template()
ist eine ~ 200-Zeilen-Funktion, die viele Dinge erledigt, die ich auch für maximale Kernkompatibilität tun möchte.
Sobald ich jedoch anrufe comments_template()
, ist eine Datei require
d, es ist die erste von:
- die Datei in der Konstante
COMMENTS_TEMPLATE
, falls definiert comments.php
im Themenordner, falls gefunden/theme-compat/comments.php
in WP enthält Ordner als letzten Ausweg Fallback
Kurz gesagt, es gibt keine Möglichkeit, die Funktion zum Laden einer PHP-Datei zu verhindern, was für mich nicht wünschenswert ist, da ich meine Vorlagen rendern und nicht einfach verwenden muss require
.
Aktuelle Lösung
Im Moment versende ich eine leere comments.php
Datei und verwende 'comments_template'
Filter Hook, um zu wissen, welche Vorlage WordPress laden möchte, und verwende die Funktion meiner Vorlagen-Engine, um die Vorlage zu laden.
Etwas wie das:
function engineCommentsTemplate($myEngine) {
$toLoad = null; // this will hold the template path
$tmplGetter = function($tmpl) use(&$toLoad) {
$toLoad = $tmpl;
return $tmpl;
};
// late priority to allow filters attached here to do their job
add_filter('comments_template', $tmplGetter, PHP_INT_MAX);
// this will load an empty comments.php file I ship in my theme
comments_template();
remove_filter('comments_template', $tmplGetter, PHP_INT_MAX);
if (is_file($toLoad) && is_readable($toLoad)) {
return $myEngine->render($toLoad);
}
return '';
}
Die Frage
Dies funktioniert, ist kernkompatibel, aber ... gibt es eine Möglichkeit, es zum Laufen zu bringen, ohne ein leeres Schiff versenden zu müssen comments.php
?
Weil ich es nicht mag.
comments_template
Filter oderCOMMENTS_TEMPLATE
Konstanten zum Anpassen der Vorlage zu verwenden. Das ist nicht entscheidend, aber wie gesagt, ich wollte so weit wie möglich mit dem Kern kompatibel bleiben.Lösung: Verwenden Sie eine temporäre Datei mit einem eindeutigen Dateinamen
Nach vielen Sprüngen und Kriechen in die schmutzigsten Ecken von PHP formulierte ich die Frage wie folgt:
wie der Code im Kern gerade ist
Dann wurde die Frage schneller gelöst:
und das ist es. Vielleicht wäre es besser,
wp_upload_dir()
stattdessen zu verwenden :Eine andere Möglichkeit könnte sein,
get_temp_dir()
welche Wraps zu verwendenWP_TEMP_DIR
. Hinweis: Es wird seltsamerweise darauf zurückgegriffen,/tmp/
dass Dateien zwischen Neustarts nicht erhalten bleiben/var/tmp/
. Man kann am Ende einen einfachen Zeichenfolgenvergleich durchführen und den Rückgabewert überprüfen und diesen dann beheben, falls er benötigt wird - was in diesem Fall nicht der Fall ist:Um schnell zu testen, ob für eine temporäre Datei ohne Inhalt Fehler ausgegeben wurden:
Und: Keine Fehler → funktionieren.
EDIT: Wie @toscho in den Kommentaren betonte , gibt es noch einen besseren Weg, dies zu tun:
Hinweis: Laut einem Benutzerhinweis in php.net-Dokumenten unterscheidet sich das
sys_get_temp_dir()
Verhalten zwischen den Systemen. Daher wird der nachfolgende Schrägstrich entfernt und dann erneut hinzugefügt. Da der Kernfehler # 22267 behoben ist, sollte dies jetzt auch auf Win / IIS-Servern funktionieren.Ihre überarbeitete Funktion (nicht getestet):
Bonus Nr.1:
tmpfile()
wird zurückkehrenNULL
. Ja wirklich.Bonus Nr.2:
file_exists( __DIR__ )
wird zurückkehrenTRUE
. Ja, wirklich ... falls du es vergessen hast.^ Dies führt zu einem tatsächlichen Fehler im WP-Kern.
Um anderen zu helfen, in den Explorer-Modus zu wechseln und diese zu finden (schlecht bis undokumentierte Teile), fasse ich schnell zusammen, was ich versucht habe:
Versuch 1: Temporäre Datei im Speicher
Der erste Versuch, den ich unternahm, bestand darin, mithilfe von einen Stream in eine temporäre Datei zu erstellen
php://temp
. Aus den PHP-Dokumenten:Der Code:
Finden: Nein, funktioniert nicht.
Versuch 2: Verwenden Sie eine temporäre Datei
Es gibt
tmpfile()
, also warum nicht nutzen ?!Ja, so viel zu dieser Abkürzung.
Versuch 3: Verwenden Sie einen benutzerdefinierten Stream-Wrapper
Als nächstes dachte ich, ich könnte einen benutzerdefinierten Stream-Wrapper erstellen und ihn mit registrieren
stream_wrapper_register()
. Dann könnte ich eine virtuelle Vorlage aus diesem Stream verwenden, um den Kern zu täuschen, dass wir eine Datei haben. Beispielcode unten (Ich habe bereits die vollständige Klasse gelöscht und der Verlauf enthält nicht genügend Schritte…)Wieder kehrte diese
NULL
auffile_exists()
.Getestet mit PHP 5.6.20
quelle
stream_stat()
? Ich denke, dass dies das ist, wasfile_exists()
aufgerufen wird, um seine Prüfung durchzuführentempnam()
. Die Verwendung eines Cron-Jobs wird funktionieren, aber es ist zusätzlicher Aufwand ...tempnam( sys_get_temp_dir(), 'comments.php' )
Wird einmal geschrieben , können Sie den Dateinamen wiederverwenden , und die Datei ist leer , sodass nicht viele Ressourcen verwendet werden. Außerdem ist es in Ihrem Code leicht zu verstehen. Mit Abstand die beste Lösung, imho.Als @AlainSchlesser vorschlug, der Route zu folgen (und da mich nicht funktionierende Dinge immer nerven), versuchte ich erneut, einen Stream-Wrapper für virtuelle Dateien zu erstellen. Ich konnte es nicht alleine lösen (lesen: Lesen der Rückgabewerte in den Dokumenten), aber ich löste es mit Hilfe von @HPierce auf SO .
Sie müssen nur die neue Klasse als neues Protokoll registrieren:
Auf diese Weise können Sie eine virtuelle (nicht vorhandene) Datei erstellen:
Ihre Funktion kann dann überarbeitet werden in:
da der
file_exists()
check in core zurückkehrtTRUE
und derrequire $file
wirft keinen fehler.Ich muss beachten, dass ich ziemlich glücklich bin, wie sich dies herausstellte, da es bei Unit-Tests wirklich hilfreich sein könnte.
quelle