Soluções para gerar javascript / CSS dinâmico

15

Digamos que você precise gerar código javascript ou CSS que dependa do contexto atual.

Por exemplo, você tem um formulário na página inicial que aciona uma solicitação ajax ao enviar e um formulário diferente na única página. Ou, no caso de CSS, você deseja criar um tema que permita aos usuários criar seu próprio layout, alterar cores etc.

Soluções que vejo até agora:

  1. Inclua o código na seção principal do documento (ou no final no caso de JS)

  2. Faça uma solicitação especial que emita o código, como site.com?get_assets . Isso é lento porque o WP é carregado duas vezes.

  3. Armazene-o em arquivos temporários por um certo período de tempo e carregue-o a partir daí. Não é muito confiável para temas públicos ou plugins.

  4. Somente Javascript - torne estático, colocando-o em um arquivo normal que é carregado sempre. Nesse caso, você teria que fazer seu código lidar com qualquer situação

Você conhece outros? Por qual caminho você iria?

onetrickpony
fonte
Se um problema encontrado na solução 1 é o cache do navegador, o código não é atualizado na atualização da página.
Aurovrata 26/10/19

Respostas:

9

Uma opção adicional, dependendo do tipo de parâmetro que você precisa passar. Vamos chamá-lo (2a). Você também pode criar scripts PHP com saída gerada dinamicamente text/cssou text/javascriptmelhor text/html, e fornecer a eles os dados de que precisam usando os parâmetros GET em vez de carregar o WordPress. Obviamente, isso só funciona se você precisar passar um número relativamente pequeno de parâmetros relativamente compactos. Por exemplo, digamos que você precise passar apenas o URL de uma postagem ou o diretório de um arquivo ou similar, você pode fazer algo assim:

No header.php:

 <script type="text/javascript" src="<?php print get_stylesheet_directory_uri(); 
 ?>/fancy-js.php?foo=bar&amp;url=<?php print urlencode(get_permalink($post->ID)); ?>"></script>

Em fancy-js.php:

 <?php
 header("Content-type: text/javascript");
 ?>
 foo = <?php print json_encode($_GET['foo']); ?>;
 url = <?php print json_encode($_GET['url']); ?>;

etc.

Mas isso permite apenas o acesso aos dados transmitidos diretamente nos parâmetros GET; e só funcionará se o número de coisas que você precisa transmitir for relativamente pequeno e a representação dessas coisas relativamente compacta. (Basicamente, são poucos os valores numéricos ou de seqüência de caracteres - um nome de usuário, por exemplo, ou um diretório; não uma lista de todas as postagens recentes de um usuário ou algo parecido.)

Quanto a qual dessas opções é a melhor - eu não sei; isso depende do seu caso de uso. A opção (1) tem o mérito de ser simples e permitir claramente o acesso a qualquer dado do WordPress que você possa precisar, sem o impacto no desempenho de carregar o WordPress duas vezes. É quase certamente o que você deve fazer, a menos que tenha uma forte razão para não fazê-lo (por exemplo, devido ao tamanho da folha de estilo ou script que você precisa usar).

Se o tamanho se tornar grande o suficiente para causar um problema em termos de peso de uma página, experimente (2) ou (2a).

Ou então - provavelmente essa é a melhor idéia - você pode tentar separar as partes do script ou da folha de estilo que realmente usam os dados dinâmicos das partes que podem ser especificadas estaticamente. Diga que você tem uma folha de estilo que precisa receber um diretório do WordPress para definir um parâmetro de segundo plano para o elemento # my-fancy. Você pode colocar tudo isso no elemento head:

 <style type="text/css">
 #my-fancy-element {
      background-image: url(<?php print get_stylesheet_directory_uri(); ?>images/fancy.png);
      padding: 20px;
      margin: 20px;
      font-weight: bold;
      text-transform: uppercase;
      font-size: 12pt;
      /* ... KB and KB of additional styles ... */
 }
 #another-fancy-element {
     /* ... KB and KB of additional styles ... */
 }
 /* ... KB and KB of additional styles ... */
 </style>

Mas por que você precisaria fazer isso? Existe apenas uma linha aqui que depende dos dados do WordPress. Melhor dividir apenas as linhas que dependem do WordPress:

 <style type="text/css">
 #my-fancy-element {
      background-image: url(<?php print get_stylesheet_directory_uri(); ?>images/fancy.png);
 }
 </style>

Coloque todo o resto em uma folha de estilo estática carregada com um elemento de link padrão (style.css ou o que for):

 #my-fancy-element {
      /* background-image provided dynamically */
      padding: 20px;
      margin: 20px;
      font-weight: bold;
      text-transform: uppercase;
      font-size: 12pt;
      /* ... KB and KB of additional styles ... */
 }
 #another-fancy-element {
     /* ... KB and KB of additional styles ... */
 }
 /* ... KB and KB of additional styles ... */

E deixe a cascata fazer o trabalho.

O mesmo vale para JavaScript: em vez de fazer isso:

 <script type="text/javascript">
 // Here comes a huge function that uses WordPress data:
 function my_huge_function () {
     // Do a million things ...

     jQuery('#my-fancy').append('<a href="'+<?php json_encode(get_permalink($GLOBALS['post']->ID)); ?>+'">foo</a>);

     // Do a million more things ...

     my_other_function(<?php print json_encode(get_userdata($GLOBALS['post']->post_author); ?>);
 }

 function my_other_function (user) {
     // Do a million things ...
 }
 </script>

Em vez disso, coloque algo assim no elemento head:

 <script type="text/javascript">
 var WordPressPostData = {
 url: <?php print json_encode(get_permalink($GLOBALS['post']->ID)); ?>,
 author: <?php print json_encode(get_userdata($GLOBALS['post']->post_author)); ?>
 }
 </script>

Em seguida, solte o restante em um arquivo JavaScript estático, reescrevendo as funções my_huge_function () e my_other_function () para fazer uso das globais WordPressPostData.url e WordPressPostData.author.

40K de CSS ou 40K de JS quase sempre podem ser divididos em <1K que realmente depende de dados dinâmicos e o restante, que pode ser especificado em um arquivo externo estático e depois recombinado usando a cascata (para CSS) ou acessível globalmente variáveis ​​(globais, elementos DOM ou qualquer outro cubículo que você preferir, para JS).

Radgeek
fonte
Resposta brilhante!
Scrib # 30/11
2
Apenas uma pequena adição: no caso de JS, podemos usar wp_localize_sciprt para adicionar variáveis ​​dinâmicas.
Anh Tran
6

O caso de CSS dinâmico é bastante simples.

Apenas crie uma função que produza as definições dinâmicas de CSS dentro das <style type="text/css"></style>tags e, em seguida, conecte essa função wp_print_styles. por exemplo

<?php
function mytheme_dynamic_css() {
    $options = get_option( 'mytheme_options' );
    ?>
    <style type="text/css">
    /* Dynamic H1 font family */
    h1 { font-family: <?php echo $options['h1_font_family']; ?>;
    </style>
    <?php
}
add_action( 'wp_print_styles', 'mytheme_dynamic_css' );
?>

Ou, digamos que você tenha esquemas de cores pré-configurados; você pode enfileirar a folha de estilo apropriada de acordo com a configuração atual do usuário:

<?php
function mytheme_enqueue_colorscheme_stylesheet() {
    $options = get_option( 'mytheme_options' );
    $color_scheme = $options['color_scheme'];
    wp_enqueue_style( $colorscheme, get_template_directory_uri() . '/css/' . $color_scheme . '.css' );
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_colorscheme_stylesheet' );
?>

Observe que, nesse caso, a função se encaixa wp_enqueue_scripts, pois o WordPress não possui um wp_enqueue_stylesgancho de ação.

Chip Bennett
fonte
1
mesmo que 1). Isto é o que eu estou fazendo agora, mas se você tiver como 40K de CSS você recebe um documento html volumosos
onetrickpony
1
Mas esses 40K de CSS precisam ser produzidos em algum lugar , certo? E, definitivamente, o mesmo que # 1, mas é o caminho certo para injetar CSS dinâmico no WordPress. :)
Chip Bennett
2

Eu estava pensando nisso por um tempo agora. Sua pergunta me faz voltar a isso. Não tenho certeza se é uma boa ideia ou não, então eu gostaria de comentários de especialistas sobre isso.

E se eu escrever o arquivo javascript / css via php quando o administrador salvar os dados. Será uma gravação única até que o usuário altere o layout novamente (o que o usuário talvez não faça com muita frequência). Dessa forma, estamos acessando o banco de dados para as configurações do usuário apenas uma vez ao salvar os dados.

Depois de escrever o arquivo, será um arquivo javascript / css comum, portanto, não precisamos chamar o banco de dados toda vez que o tema carregar.

Uma pergunta que precisa ser respondida: O que acontecerá quando um visitante tentar acessar o site no instante em que o php estiver gravando o arquivo?

Diz-me o que pensas.

Sisir
fonte
Se você gerar esses arquivos wp-content/uploads(o único diretório garantido para gravação no código WP), poderá ser uma abordagem viável. Acho que até o WP Core usa essa técnica para um arquivo js.
Scritt 31/10/11
A desvantagem é que não é realmente dinâmico, ou seja, é o mesmo para todos em todas as páginas. Para cada variação, você precisaria gerar um novo arquivo. Ainda é uma boa abordagem para as opções de tema / plug-in, como você mencionou.
Scritt 31/10/11
@ Scribu: sim, é verdade. pode ser uma bagunça para algo assim. se fornecermos aos usuários uma página de perfil personalizada e precisarmos gravar arquivos em cada um deles. Mas pode ser uma boa abordagem para algo como se fizermos um criador de site visual (arrastar e soltar) em que o usuário altere as cores e adicione vários efeitos (como nesta pergunta) etc. e possa ser combinado com o WPMU;)
Sisir
1

Para pequenos pedaços de scripts, que talvez você não queira incluir em um arquivo separado, por exemplo, porque eles são gerados dinamicamente, o WordPress 4.5 e outras ofertas wp_add_inline_script. Essa função basicamente trava o script para outro script. Digamos, por exemplo, que você esteja desenvolvendo um tema e que seu cliente possa inserir seus próprios scripts (como Google Analytics ou AddThis) na página de opções. Exemplo .

Para estilos wp_add_inline_style, basicamente funciona da mesma maneira. Você usaria, por exemplo, para percorrer todos os seus mods do personalizador e reuni-los em uma sequência chamada $all_mods, que você adicionaria assim à sua folha de estilo principal:

if (!empty($all_mods)) wp_add_inline_style ('main-style', $all_mods);
cjbj
fonte
-2

Crie um arquivo JS.php dinâmico e alimente importantes query_vars. Essas variáveis $_GETajudarão o arquivo a determinar o contexto e nele você pode armazenar em cache e usar readfile()para solicitações futuras ... faça o que for.

Apenas certifique-se de que o arquivo carregue wp-load.phpantes de qualquer outra coisa, para ter acesso às funções do WP. Use o caminho relativo para a pasta atual (dirname(__FILE__))ou apenas desça na estrutura da pasta para localizar, wp-load.phpindependentemente do posicionamento do plug-in.

Código para procurar o wp-load.php de qualquer lugar

// Ensure single declaration of function!
if(!function_exists('wp_locate_loader')):
    /**
     * Locates wp-load.php looking backwards on the directory structure.
     * It start from this file's folder.
     * Returns NULL on failure or wp-load.php path if found.
     * 
     * @author EarnestoDev
     * @return string|null
     */
    function wp_locate_loader(){
        $increments = preg_split('~[\\\\/]+~', dirname(__FILE__));
        $increments_paths = array();
        foreach($increments as $increments_offset => $increments_slice){
            $increments_chunk = array_slice($increments, 0, $increments_offset + 1);
            $increments_paths[] = implode(DIRECTORY_SEPARATOR, $increments_chunk);
        }
        $increments_paths = array_reverse($increments_paths);
        foreach($increments_paths as $increments_path){
            if(is_file($wp_load = $increments_path.DIRECTORY_SEPARATOR.'wp-load.php')){
                return $wp_load;
            }
        }
        return null;
    }
endif;
// Now try to load wp-load.php and pull it in
$mt = microtime(true);
if(!is_file($wp_loader = wp_locate_loader())){
    header("{$_SERVER['SERVER_PROTOCOL']} 403 Forbidden");
    header("Status: 403 Forbidden");
    echo 'Access denied!'; // Or whatever
    die;
}
require_once($wp_loader); // Pull it in
unset($wp_loader); // Cleanup variables

Saúde, Scribu!

PS : Para estruturas complicadas em que as pastas não seguem a estrutura decremental normal do WP, os plugins pai podem compartilhar informações com arquivos diretamente acessíveis. Um plugin pai que vem com um arquivo PHP dinâmico que torna CSS / JS pode escrever em um arquivo ao realpath()do wp-load.phpeo arquivo autônomo pode usar isso. Isso seria um problema para 0,1% dos usuários do WP. Eu acho que aqueles que movem pastas e não seguem a estrutura normal sabem o que estão fazendo e provavelmente podem plugins PIMP que precisam carregar wp-load.phpdiretamente.

EarnestoDev
fonte
Fofa! Aborrecedores, por favor, acrescente explicações. Me esclareça. Obrigado;) xoxo
EarnestoDev
É uma prática ruim incluir wp-load.phpum tema ou arquivo de plug-in, pois os diretórios wp-contente / ou pluginspodem estar em qualquer lugar em relação ao diretório WP raiz. Lembre-se de WP_CONTENT_DIR e WP_PLUGINS_DIR.
Scrib # 30/11
1
@scribu E o arquivo autônomo pode colaborar com um plug-in pai. O plugin pai pode armazenar o wp-load.php na pasta em que está localizado e o gerador js dinâmico pode lê-lo a partir daí. Simples ...
EarnestoDev 30/10
1
Sim, a abordagem do plugin pai pode funcionar. Escreva na sua resposta e eu removerei meu voto negativo. PS: Este site está em inglês; você pode ter problemas se continuar a fazer comentários em romeno.
Scrib # 30/11
5
Corte a atitude. A carga manual do núcleo é uma técnica viável, mas está longe de ser uma boa escolha para a maioria das coisas. Ninguém duvida que você pode fazê-lo funcionar. Os votos são sobre a qualidade da sua resposta, não do seu cérebro.
Rarst