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

13

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

Por exemplo, você tem um formulário na página inicial que dispara uma solicitação ajax no envio e um formulário diferente na página única. Ou, no caso do 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 head do documento (ou no final no caso de JS)

  2. Faça uma solicitação especial que produza 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 determinado período de tempo e carregue-o de lá. Não é muito confiável para temas ou plug-ins públicos.

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

Você conhece os outros? Qual caminho você iria?

    
por onetrickpony 29.10.2011 / 16:56

5 respostas

8

Uma opção adicional, dependendo do tipo de parâmetros que você precisa passar. Vamos chamá-lo (2a). Você também pode criar scripts PHP com saída text/css ou text/javascript gerada dinamicamente, em vez de text/html , e fornecer os dados necessários usando os parâmetros GET, em vez de carregar o WordPress. Claro que isso só funciona se você precisar passar um número relativamente pequeno de parâmetros relativamente compactos. Por exemplo, digamos que você precise transmitir apenas a URL de um post 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 só permite o acesso aos dados transmitidos diretamente nos parâmetros GET; e só funcionará se o número de coisas que você precisar passar for relativamente pequeno, e a representação dessas coisas relativamente compactas. (Basicamente um punhado de string ou valores numéricos - um nome de usuário, digamos, ou um diretório; não uma lista de todos os posts recentes de um usuário ou algo assim.)

Quanto a qual dessas opções é a melhor - 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 quaisquer dados do WordPress que você possa precisar, sem o impacto no desempenho de carregar o WordPress duas vezes. É quase certo o que você deve fazer, a menos que você tenha uma strong 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 da sua página, você poderá experimentar (2) ou (2a).

Ou então - esta é provavelmente a melhor idéia - você pode tentar separar as partes do script ou a folha de estilo que realmente fazem uso dos dados dinâmicos das partes que podem ser especificadas estaticamente. Diga que você tem uma folha de estilo que precisa passar por um diretório do WordPress para definir um parâmetro de fundo para o elemento # my-fancy. Você poderia colocar tudo isso no elemento principal:

 <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ê precisa fazer isso? Há 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 que você carrega com um elemento de link padrão (style.css ou qualquer outro):

 #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, descarte o restante em um arquivo JavaScript estático, reescrevendo o my_huge_function () e o my_other_function () para fazer uso dos globais WordPressPostData.url e WordPressPostData.author.

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

    
por radgeek 30.10.2011 / 16:05
5

O caso do CSS dinâmico é bastante simples.

Basta criar uma função que exiba as definições dinâmicas de CSS dentro de <style type="text/css"></style> tags e, em seguida, associe essa função a 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 é conectada a wp_enqueue_scripts , pois o WordPress não possui um gancho de ação wp_enqueue_styles .

    
por Chip Bennett 29.10.2011 / 18:44
2

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

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

Depois de escrever o arquivo, ele será um arquivo javascript / css comum, para que não tenhamos que chamar o banco de dados toda vez que o tema for carregado.

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

Deixe-me saber o que você pensa.

    
por Sisir 31.10.2011 / 12:27
1

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

Para estilos, há wp_add_inline_style , que basicamente funciona da mesma forma. Você poderia usá-lo, por exemplo, para percorrer todos os seus modificadores personalizadores e reuni-los em uma string chamada $all_mods , que você adicionaria assim à sua folha de estilo principal:

if (!empty($all_mods)) wp_add_inline_style ('main-style', $all_mods);
    
por cjbj 31.10.2016 / 10:09
-2

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

Apenas certifique-se de que o arquivo carrega o wp-load.php antes de mais nada, para que você tenha acesso às funções do WP. Use caminho relativo para a pasta atual (dirname(__FILE__)) ou apenas digg descendente na estrutura de pastas para localizar wp-load.php independentemente do posicionamento do plug-in.

Código para buscar 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

Felicidades, Scribu!

PS : Para estruturas complicadas em que as pastas não seguem a estrutura decrescente normal do WP, os plug-ins pai podem compartilhar informações com arquivos diretamente acessíveis. Um plug-in pai que vem com um arquivo PHP dinâmico que renderiza CSS / JS pode gravar em um arquivo. O realpath() do wp-load.php e o arquivo independente podem usá-lo. 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 os plugins PIMP que precisam carregar wp-load.php diretamente.

    
por EarnestoDev 29.10.2011 / 17:51