Estou desenvolvendo um tema WordPress usando um mecanismo de modelo. Quero que meu código seja o mais compatível possível com a funcionalidade principal do WP.
Algum contexto primeiro
Meu primeiro problema foi encontrar uma maneira de resolver o modelo a partir de uma consulta WP. Eu resolvi aquele usando uma biblioteca minha, Brain \ Hierarchy .
Com relação get_template_part()
e outras funções que cargas parciais gosto get_header()
, get_footer()
e semelhantes, que era muito fácil escrever wrapper para a funcionalidade parcial modelo de motor.
O problema
Meu problema agora é como carregar o modelo de comentários.
A função WordPress comments_template()
é uma função de ~ 200 linhas que faz muitas coisas, o que eu quero fazer também para obter a compatibilidade máxima do núcleo.
No entanto, assim que eu chamo comments_template()
, um arquivo é require
d, é o primeiro de:
- o arquivo na constante
COMMENTS_TEMPLATE
, se definido comments.php
na pasta do tema, se encontrado/theme-compat/comments.php
no WP inclui pasta como fallback de último recurso
Em suma, não há como impedir que a função carregue um arquivo PHP, o que não é desejável para mim, porque preciso renderizar meus modelos e não simplesmente usá-lo require
.
Solução atual
No momento, estou enviando um comments.php
arquivo vazio e estou usando o 'comments_template'
gancho de filtro para saber qual modelo o WordPress deseja carregar e usar o recurso do meu mecanismo de modelos para carregar o modelo.
Algo assim:
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 '';
}
A questão
Isso funciona, é compatível com o núcleo, mas ... existe uma maneira de fazê-lo funcionar sem ter que enviar um vazio comments.php
?
Porque eu não gosto disso.
comments_template
filtro ouCOMMENTS_TEMPLATE
constante para personalizar o modelo. O que não é crucial, mas, como eu disse, queria permanecer o máximo possível compatível com o núcleo.Solução: use um arquivo temporário - com um nome de arquivo exclusivo
Depois de muitos saltos e rastejando pelos cantos mais sujos do PHP, reformulei a pergunta para:
como o código no núcleo é apenas
Então a questão foi resolvida mais rapidamente:
e é isso. Talvez seja melhor usar
wp_upload_dir()
:Outra opção pode ser usar
get_temp_dir()
quais bandagensWP_TEMP_DIR
. Dica: estranhamente, ele volta para/tmp/
que os arquivos não sejam preservados entre as reinicializações, o que/var/tmp/
ocorreria. Pode-se fazer uma comparação simples de strings no final e verificar o valor de retorno e, em seguida, corrigir isso no caso de ser necessário - o que não é o caso:Agora, para testar rapidamente se há erros gerados para um arquivo temporário sem conteúdo:
E: Sem erros → trabalhando.
EDIT: Como @toscho apontou nos comentários, ainda há uma maneira melhor de fazer isso:
Nota: De acordo com uma nota de usuário nos documentos do php.net , o
sys_get_temp_dir()
comportamento difere entre os sistemas. Portanto, o resultado obtém a barra à direita removida e adicionada novamente. Como o principal erro 22267 foi corrigido, agora também deve funcionar nos servidores Win / IIS.Sua função refatorada (não testada):
Bônus Nr.1:
tmpfile()
retornaráNULL
. Sim mesmo.Bônus Nr.2:
file_exists( __DIR__ )
retornaráTRUE
. Sim, realmente ... caso você tenha esquecido.^ Isso leva a um bug real no núcleo do WP.
Para ajudar outras pessoas a entrar no modo explorador e a encontrá-las (mal em partes não documentadas), resumirei rapidamente o que tentei:
Tentativa 1: arquivo temporário na memória
A primeira tentativa que fiz foi criar um fluxo para um arquivo temporário usando
php://temp
. Nos documentos do PHP:O código:
Encontrar: Não, não funciona.
Tentativa 2: usar um arquivo temporário
Há
tmpfile()
, então por que não usar isso ?!Sim, muito sobre esse atalho.
Tentativa 3: Use um wrapper de fluxo personalizado
Em seguida, pensei em criar um wrapper de fluxo personalizado e registrá-lo usando
stream_wrapper_register()
. Então eu poderia usar um modelo virtual desse fluxo para induzir o núcleo a acreditar que temos um arquivo. Exemplo de código abaixo (eu já excluí a classe completa e o histórico não possui etapas suficientes ...)Novamente, isso voltou
NULL
emfile_exists()
.Testado com PHP 5.6.20
fonte
stream_stat()
? Eu acho que isso é ofile_exists()
que chamará para fazer a sua verificação ... php.net/manual/en/streamwrapper.stream-stat.phptempnam()
. Usar um trabalho cron funcionará, mas é uma sobrecarga adicional ...tempnam( sys_get_temp_dir(), 'comments.php' )
é gravado uma vez , você pode reutilizar o nome do arquivo, e o arquivo está vazio , portanto, ele não usa muitos recursos. Além disso, é fácil entender o seu código. De longe a melhor solução, imho.Como o @AlainSchlesser sugeriu seguir a rota (e como as coisas não funcionais sempre me incomodam ), tentei criar um wrapper de fluxo para arquivos virtuais. Não consegui resolvê-lo (leia-se: lendo os valores de retorno nos documentos) sozinho, mas o resolvi com a ajuda do @HPierce on SO .
Você só precisa registrar a nova classe como novo protocolo:
Isso permite criar um arquivo virtual (não existente):
Sua função pode ser refatorada para:
como o
file_exists()
check-in principal retornaTRUE
erequire $file
não gera erro.Devo observar que estou muito feliz com o resultado, pois pode ser realmente útil nos testes de unidade.
fonte