Je développe un thème WordPress à l'aide d'un moteur de modèle. Je veux que mon code soit aussi compatible que possible avec les fonctionnalités de base de WP.
Un peu de contexte d'abord
Mon premier problème a été de trouver un moyen de résoudre le modèle à partir d'une requête WP. J'ai résolu celui-ci en utilisant une de mes bibliothèques, Brain \ Hierarchy .
En ce qui concerne get_template_part()
et d' autres fonctions qui charge comme partials get_header()
, get_footer()
et similaire, il était assez facile à wrapper d'écriture sur le moteur de template fonctionnalité partielle.
Le problème
Mon problème est maintenant de savoir comment charger le modèle de commentaires.
La fonction WordPress comments_template()
est une fonction de ~ 200 lignes qui fait beaucoup de choses, ce que je veux aussi faire pour une compatibilité maximale avec le cœur.
Cependant, dès que j'appelle comments_template()
, un fichier est require
d, c'est le premier de:
- le fichier dans la constante
COMMENTS_TEMPLATE
, si définie comments.php
dans le dossier du thème, s'il est trouvé/theme-compat/comments.php
dans WP inclut le dossier en dernier recours
En bref, il n'y a aucun moyen d'empêcher la fonction de charger un fichier PHP, ce qui n'est pas souhaitable pour moi, car j'ai besoin de rendre mes modèles et pas simplement d'utiliser require
.
Solution actuelle
En ce moment, j'expédie un comments.php
fichier vide et j'utilise un 'comments_template'
crochet de filtre, pour savoir quel modèle WordPress veut charger, et utiliser la fonctionnalité de mon moteur de modèle pour charger le modèle.
Quelque chose comme ça:
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 '';
}
La question
Cela fonctionne, est compatible avec le noyau, mais ... existe-t-il un moyen de le faire fonctionner sans avoir à expédier un vide comments.php
?
Parce que je n'aime pas ça.
comments_template
filtre ou d'uneCOMMENTS_TEMPLATE
constante pour personnaliser le modèle. Ce qui n'est pas essentiel, mais, comme je l'ai dit, je voulais rester le plus possible compatible avec le core.Solution: utilisez un fichier temporaire - avec un nom de fichier unique
Après beaucoup de sauts et de ramper dans les coins les plus sales de PHP, j'ai reformulé la question juste:
comme le code dans le noyau est juste
Ensuite, la question a été résolue plus rapidement:
et c'est tout. Il serait peut-être préférable d'utiliser à la
wp_upload_dir()
place:Une autre option pourrait consister à utiliser les
get_temp_dir()
enveloppesWP_TEMP_DIR
. Astuce: Cela revient étrangement à/tmp/
ce que les fichiers ne soient pas conservés entre les redémarrages, ce qui/var/tmp/
serait le cas. On peut faire une simple comparaison de chaînes à la fin et vérifier la valeur de retour, puis corriger cela au cas où cela serait nécessaire - ce qui n'est pas le cas:Maintenant, pour tester rapidement s'il y a des erreurs lancées pour un fichier temporaire sans contenu:
Et: aucune erreur → travail.
EDIT: Comme @toscho l'a souligné dans les commentaires, il existe encore une meilleure façon de le faire:
Remarque: Selon une note des utilisateurs sur les documents php.net , le
sys_get_temp_dir()
comportement diffère selon les systèmes. Par conséquent, le résultat obtient la barre oblique de fin supprimée, puis ajoutée à nouveau. Comme le bogue de base # 22267 est corrigé, cela devrait également fonctionner sur les serveurs Win / IIS.Votre fonction refactorisée (non testée):
Bonus Nr.1:
tmpfile()
reviendraNULL
. Ouais vraiment.Bonus Nr.2:
file_exists( __DIR__ )
reviendraTRUE
. Oui, vraiment… au cas où tu aurais oublié.^ Cela conduit à un bug réel dans WP core.
Pour aider les autres à passer en mode explorateur et à les retrouver (mal à des pièces non documentées), je résumerai rapidement ce que j'ai essayé:
Tentative 1: fichier temporaire en mémoire
La première tentative que j'ai faite a été de créer un flux vers un fichier temporaire à l'aide de
php://temp
. Depuis les documents PHP:Le code:
Conclusion: Non, ne fonctionne pas.
Tentative 2: utiliser un fichier temporaire
Il y a
tmpfile()
, alors pourquoi ne pas utiliser ça?!Ouais, ça à propos de ce raccourci.
Tentative 3: utilisez un wrapper de flux personnalisé
Ensuite, je pensais pouvoir créer un wrapper de flux personnalisé et l' enregistrer à l'aide
stream_wrapper_register()
. Ensuite, je pourrais utiliser un modèle virtuel de ce flux pour inciter le noyau à croire que nous avons un fichier. Exemple de code ci-dessous (j'ai déjà supprimé la classe complète et l'historique n'a pas assez d'étapes…)Encore une fois, cela est revenu
NULL
surfile_exists()
.Testé avec PHP 5.6.20
la source
stream_stat()
? Je pense que c'est ce quifile_exists()
va appeler pour faire son chèque ... php.net/manual/en/streamwrapper.stream-stat.phptempnam()
. Utiliser un travail cron fonctionnera, mais c'est un surcoût supplémentaire ...tempnam( sys_get_temp_dir(), 'comments.php' )
est écrit une fois , vous pouvez réutiliser le nom de fichier et le fichier est vide , donc il n'utilise pas beaucoup de ressources. De plus, il est facile à comprendre dans votre code. De loin la meilleure solution, à mon humble avis.Comme @AlainSchlesser a suggéré de suivre l'itinéraire (et comme les choses qui ne fonctionnent pas me dérangent toujours), j'ai réessayé de créer un wrapper de flux pour les fichiers virtuels. Je n'ai pas pu le résoudre (lire: lire les valeurs de retour sur les documents) par moi-même, mais je l'ai résolu avec l'aide de @HPierce sur SO .
Vous avez juste besoin d'enregistrer la nouvelle classe en tant que nouveau protocole:
Cela permet alors de créer un fichier virtuel (non existant):
Votre fonction peut alors être refactorisée pour:
comme le
file_exists()
retour dans le noyau retourneTRUE
etrequire $file
ne génère aucune erreur.Je dois noter que je suis assez heureux de la façon dont cela s'est avéré, car cela pourrait être très utile avec les tests unitaires.
la source