Saya sedang mengembangkan tema WordPress menggunakan mesin template. Saya ingin kode saya menjadi kompatibel sebanyak mungkin dengan fungsionalitas WP core.
Beberapa konteks dulu
Masalah pertama saya adalah menemukan cara untuk menyelesaikan template mulai dari permintaan WP. Saya memecahkan yang menggunakan perpustakaan saya, Brain \ Hierarchy .
Mengenai get_template_part()
dan fungsi-fungsi lain yang memuat parsial suka get_header()
, get_footer()
dan serupa, itu cukup mudah untuk menulis wrapper ke templat fungsionalitas mesin parsial.
Masalah
Masalah saya sekarang adalah bagaimana memuat template komentar.
Fungsi WordPress comments_template()
adalah fungsi ~ 200 baris yang melakukan banyak hal, yang ingin saya lakukan juga untuk kompatibilitas inti maksimum.
Namun, begitu saya menelepon comments_template()
, file require
d, itu adalah yang pertama dari:
- file dalam konstanta
COMMENTS_TEMPLATE
, jika ditentukan comments.php
di folder tema, jika ditemukan/theme-compat/comments.php
di WP menyertakan folder sebagai fallback pilihan terakhir
Singkatnya, tidak ada cara untuk mencegah fungsi memuat file PHP, yang tidak diinginkan bagi saya, karena saya perlu membuat template saya dan tidak hanya menggunakan require
.
Solusi saat ini
Saat ini, saya mengirimkan comments.php
file kosong dan saya menggunakan 'comments_template'
hook filter, untuk mengetahui template yang ingin dimuat WordPress, dan menggunakan fitur dari mesin template saya untuk memuat template.
Sesuatu seperti ini:
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 '';
}
Pertanyaan
Ini berfungsi, apakah core kompatibel, tetapi ... adakah cara untuk membuatnya berfungsi tanpa harus mengirimkan yang kosong comments.php
?
Karena saya tidak suka itu.
comments_template
filter atauCOMMENTS_TEMPLATE
konstan untuk menyesuaikan template. Yang tidak penting, tetapi, seperti yang saya katakan, saya ingin tetap sebisa mungkin kompatibel dengan inti.Solusi: Gunakan file sementara - dengan nama file unik
Setelah banyak lompatan dan merangkak ke sudut-sudut paling kotor dari PHP, saya mengulang pertanyaan itu menjadi:
sebagai kode dalam inti saja
Kemudian pertanyaan itu diselesaikan lebih cepat:
dan hanya itu. Mungkin lebih baik digunakan
wp_upload_dir()
sebagai gantinya:Pilihan lain mungkin menggunakan
get_temp_dir()
wrapsWP_TEMP_DIR
. Petunjuk: Anehnya kembali ke/tmp/
sehingga file tidak akan diawetkan antara reboot, yang/var/tmp/
akan. Seseorang dapat melakukan perbandingan string sederhana di akhir dan memeriksa nilai kembali dan kemudian memperbaikinya jika diperlukan - yang tidak dalam hal ini:Sekarang untuk dengan cepat menguji apakah ada kesalahan yang dilemparkan untuk file sementara tanpa konten:
Dan: Tidak Ada Kesalahan → berfungsi.
EDIT: Seperti @toscho tunjukkan dalam komentar, masih ada cara yang lebih baik untuk melakukannya:
Catatan: Menurut catatan pengguna pada dokumen php.net ,
sys_get_temp_dir()
perilaku ini berbeda di antara sistem. Oleh karena itu hasilnya menghilangkan garis miring dihapus, lalu ditambahkan lagi. Karena bug inti # 22267 diperbaiki, ini juga dapat bekerja pada server Win / IIS sekarang.Fungsi refactored Anda (tidak diuji):
Bonus No. 1:
tmpfile()
akan kembaliNULL
. Ya benarBonus No. 2:
file_exists( __DIR__ )
akan kembaliTRUE
. Ya, sungguh ... kalau-kalau Anda lupa.^ Ini mengarah ke bug aktual di WP core.
Untuk membantu orang lain dalam mode penjelajah dan menemukan (bagian yang tidak berdokumen), saya akan dengan cepat meringkas apa yang saya coba:
Percobaan 1: File sementara di memori
Upaya pertama yang saya lakukan adalah membuat aliran ke file sementara, menggunakan
php://temp
. Dari dokumen PHP:Kode:
Temuan: Tidak, tidak berfungsi.
Percobaan 2: Gunakan file sementara
Ada
tmpfile()
, jadi mengapa tidak menggunakannya ?!Ya, itu banyak tentang cara pintas ini.
Percobaan 3: Gunakan pembungkus aliran khusus
Selanjutnya saya pikir saya bisa membangun pembungkus aliran khusus dan mendaftar menggunakan
stream_wrapper_register()
. Lalu saya bisa menggunakan templat virtual dari aliran itu untuk menipu inti agar percaya bahwa kita memiliki file. Contoh kode di bawah ini (saya sudah menghapus seluruh kelas dan sejarah tidak memiliki langkah yang cukup ...)Sekali lagi, ini kembali
NULL
padafile_exists()
.Diuji dengan PHP 5.6.20
sumber
stream_stat()
? Saya pikir inilah yangfile_exists()
akan dipanggil untuk memeriksa ... php.net/manual/en/streamwrapper.stream-stat.phptempnam()
. Menggunakan pekerjaan cron akan berhasil, tapi itu overhead tambahan ...tempnam( sys_get_temp_dir(), 'comments.php' )
ditulis sekali , Anda dapat menggunakan kembali nama file, dan file tersebut kosong , sehingga tidak menggunakan banyak sumber. Plus mudah untuk dipahami dalam kode Anda. Sejauh ini solusi terbaik, imho.Sebagai @AlainSchlesser menyarankan untuk mengikuti rute (dan karena hal-hal yang tidak bekerja selalu mengganggu saya), saya mencoba membangun pembungkus aliran untuk file virtual. Saya tidak bisa menyelesaikannya (baca: membaca nilai-nilai pengembalian pada dokumen) sendiri, tetapi menyelesaikannya dengan bantuan @HPierce pada SO .
Anda hanya perlu mendaftarkan kelas baru sebagai protokol baru:
Ini kemudian memungkinkan untuk membuat file virtual (tidak ada):
Fungsi Anda kemudian dapat di refactored ke:
sebagai
file_exists()
check in core kembaliTRUE
danrequire $file
tidak ada kesalahan melempar.Saya harus mencatat bahwa saya cukup senang bagaimana ini ternyata karena mungkin sangat membantu dengan unit test.
sumber