Soluciones para generar javascript / CSS dinámico

15

Digamos que necesita generar código javascript o CSS que depende del contexto actual.

Por ejemplo, tiene un formulario en la página de inicio que dispara una solicitud ajax al enviarlo, y un formulario diferente en la página única. O, en el caso de CSS, desea crear un tema que permita a sus usuarios crear su propio diseño, cambiar colores, etc.

Soluciones que veo hasta ahora:

  1. Incluya el código en la sección principal del documento (o al final en el caso de JS)

  2. Haga una solicitud especial que muestre el código, como site.com?get_assets . Esto es lento porque WP se carga dos veces.

  3. Almacénelo en archivos temporales durante un cierto período de tiempo y cárguelo desde allí. No es muy confiable para temas públicos o complementos.

  4. Solo Javascript: hágalo estático colocándolo en un archivo normal que se carga cada vez. En este caso, deberías hacer que tu código maneje cualquier situación

¿Conoces a otros? ¿Qué camino deberías elegir?

Pony de un solo truco
fuente
Un problema que encontré con la solución 1 es el almacenamiento en caché por parte del navegador, el código no se actualiza en la recarga de la página.
Aurovrata

Respuestas:

9

Una opción adicional, dependiendo del tipo de parámetros que necesita pasar. Llamemos (2a). También puede crear scripts PHP que generen dinámicamente text/csso text/javascriptno text/html, y proporcionarles los datos que necesitan utilizando los parámetros GET en lugar de cargar WordPress. Por supuesto, esto solo funciona si necesita pasar un número relativamente pequeño de parámetros relativamente compactos. Entonces, por ejemplo, digamos que necesita pasar solo la URL de una publicación o el directorio de un archivo o similar, puede hacer algo como esto:

En 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>

En fancy-js.php:

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

etc.

Pero esto solo le permite acceder a los datos directamente pasados ​​en los parámetros GET; y solo funcionará si la cantidad de cosas que necesita pasar es relativamente pequeña, y la representación de esas cosas es relativamente compacta. (Básicamente, un puñado de cadenas o valores numéricos: un nombre de usuario, digamos o un directorio; no una lista de todas las publicaciones recientes de un usuario o algo así).

En cuanto a cuál de estas opciones es la mejor, no lo sé; eso depende de su caso de uso. La opción (1) tiene el mérito de ser simple y claramente permitirle acceder a cualquier información de WordPress que pueda necesitar, sin el impacto en el rendimiento de cargar WordPress dos veces. Es casi seguro lo que debe hacer a menos que tenga una buena razón para no hacerlo (por ejemplo, debido al tamaño de la hoja de estilo o script que necesita usar).

Si el tamaño se vuelve lo suficientemente grande como para causar un problema en términos del peso de su página, puede probar (2) o (2a).

O bien, esta es probablemente la mejor idea, puede intentar separar las partes del guión o la hoja de estilo que realmente utilizan los datos dinámicos de las partes que pueden especificarse estáticamente. Di que tienes una hoja de estilo que necesita pasar un directorio de WordPress para establecer un parámetro de fondo para el elemento # my-fancy. Podrías poner todo esto en el 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>

¿Pero por qué necesitarías hacer eso? Aquí solo hay una línea que depende de los datos de WordPress. Es mejor dividir solo las líneas que dependen de WordPress:

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

Coloque todo lo demás en una hoja de estilo estática que cargue con un elemento de enlace estándar (style.css o lo que sea):

 #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 ... */

Y deja que la cascada haga el trabajo.

Lo mismo ocurre con JavaScript: en lugar de hacer esto:

 <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>

En su lugar, coloque algo como esto en el elemento principal:

 <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>

Y luego suelte el resto en un archivo JavaScript estático, reescribiendo my_huge_function () y my_other_function () para hacer uso de los globales WordPressPostData.url y WordPressPostData.author.

40K de CSS o 40K de JS casi siempre se pueden dividir en <1K que realmente depende de datos dinámicos, y el resto, que se puede especificar en un archivo externo estático y luego recombinar usando la cascada (para CSS) o accesible globalmente variables (globales, elementos DOM o cualquier otro cubículo que prefiera, para JS).

radgeek
fuente
Brillante respuesta!
scribu
2
Solo una pequeña adición: en el caso de JS, podemos usar wp_localize_sciprt para agregar variables dinámicas.
Anh Tran
6

El caso de CSS dinámico es bastante simple.

Simplemente cree una función que genere las definiciones dinámicas de CSS dentro de las <style type="text/css"></style>etiquetas y luego conecte esa función wp_print_styles. p.ej

<?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' );
?>

O, digamos que tiene esquemas de color preconfigurados; puede poner en cola la hoja de estilo apropiada de acuerdo con la configuración actual del usuario:

<?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' );
?>

Tenga en cuenta que, en este caso, la función se conecta wp_enqueue_scripts, ya que WordPress no tiene un wp_enqueue_stylesenlace de acción.

Chip Bennett
fuente
1
igual que 1). Esto es lo que estoy haciendo ahora, pero si tienes como 40K de CSS obtienes un documento html voluminoso
onetrickpony
1
Pero esos 40K de CSS tienen que salir en alguna parte , ¿verdad? Y, definitivamente, es el mismo que el # 1, pero es la forma correcta de inyectar CSS dinámico en WordPress. :)
Chip Bennett
2

Estaba pensando eso por un tiempo ahora. Tu pregunta me hace volver a ella. No estoy seguro de si es una buena idea o no, así que me gustaría que los expertos comentaran al respecto.

¿Qué sucede si escribo el archivo javascript / css a través de php cuando el administrador guarda los datos? Será una escritura única hasta que el usuario vuelva a cambiar el diseño (que el usuario no puede hacer con demasiada frecuencia). De esta forma, solo accedemos a la base de datos para la configuración del usuario una vez que el usuario guarda datos.

Después de escribir el archivo, será un archivo javascript / css normal, por lo que no tenemos que llamar a la base de datos cada vez que se carga el tema.

Una pregunta que necesita respuesta: ¿Qué sucederá cuando un visitante intente acceder al sitio en el instante en que php escriba el archivo?

Déjame saber lo que piensas.

Sisir
fuente
Si genera esos archivos en wp-content/uploads(el único directorio que se puede escribir desde el código WP), podría ser un enfoque viable. Creo que incluso WP Core usa esta técnica para un archivo js.
scribu
El inconveniente es que no es realmente dinámico, es decir, es el mismo para todos en todas las páginas. Para cada variación, tendría que generar un nuevo archivo. Todavía es un buen enfoque para las opciones de tema / complemento, como mencionó.
scribu
@scribu: sí, es verdad. Puede ser un desastre para algo así. si les damos a los usuarios una página de perfil personalizada y tenemos que escribir archivos cada uno de ellos Pero podría ser un buen enfoque para algo como si hacemos un creador visual de sitios web (arrastrar y soltar) donde el usuario cambia los colores y agrega varios efectos (a partir de esta pregunta), etc. y puede combinarse con WPMU;)
Sisir
1

Para pequeñas secuencias de comandos, que quizás no desee incluir en un archivo separado, por ejemplo, porque se generan dinámicamente, WordPress 4.5 y otras ofertas wp_add_inline_script. Esta función básicamente bloquea el script con otro script. Digamos, por ejemplo, que está desarrollando un tema y desea que su cliente pueda insertar sus propios scripts (como Google Analytics o AddThis) a través de la página de opciones. Ejemplo .

Para los estilos hay wp_add_inline_style, que básicamente funciona igual. Lo usaría, por ejemplo, para recorrer todos sus mods de personalización y reunirlos en una cadena llamada $all_mods, que luego agregaría de esta manera a su hoja de estilo principal:

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

Cree un archivo JS.php dinámico y aliméntelo con query_vars importantes. Esas variables $_GETayudarán al archivo a determinar el contexto y en él puede almacenar en caché y usar readfile()para futuras solicitudes ... haga lo que sea.

Solo asegúrese de que el archivo cargue wp-load.phpantes que cualquier otra cosa, para que tenga acceso a las funciones de WP. Use la ruta relativa a la carpeta actual (dirname(__FILE__))o simplemente digg descendiendo en la estructura de la carpeta para ubicarlo wp-load.phpindependientemente de la ubicación del complemento.

Código para buscar wp-load.php desde cualquier 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

Saludos, Scribu!

PD : Para estructuras complicadas donde las carpetas no siguen la estructura decremental WP normal, los complementos principales pueden compartir información con archivos directamente accesibles. Un complemento padre que viene con un archivo PHP dinámico que procesa CSS / JS puede escribir en un archivo realpath()el wp-load.phpy el archivo independiente puede usar eso. Esto sería un problema para el 0.1% de los usuarios de WP. Creo que aquellos que mueven carpetas y no siguen la estructura normal saben lo que están haciendo y probablemente puedan agregar complementos PIMP que deben cargarse wp-load.phpdirectamente.

EarnestoDev
fuente
¡Linda! Odiadores, por favor agregue explicaciones. Iluminame. Gracias;) xoxo
EarnestoDev
Es una mala práctica incluir wp-load.phpdesde un tema o un archivo de complemento, ya que los directorios wp-contenty / o pluginspodrían estar en cualquier lugar en relación con el directorio raíz de WP. Recuerde WP_CONTENT_DIR y WP_PLUGINS_DIR.
scribu
1
@scribu Y el archivo independiente puede colaborar con un complemento principal. El complemento principal puede almacenar wp-load.php en la carpeta donde está ubicado y el generador js dinámico puede leerlo desde allí. Simple ...
EarnestoDev
1
Sí, el enfoque del complemento principal podría funcionar. Escríbelo en tu respuesta y eliminaré mi voto negativo. PD: este sitio está en inglés; puede tener problemas si continúa dejando comentarios en rumano.
scribu
55
Cortar la actitud. La carga central manual es una técnica viable, pero está lejos de ser una buena primera elección para la mayoría de las cosas. Nadie duda de que puedes hacer que funcione. Los votos son sobre la calidad de su respuesta, no sobre su cerebro.
Rarst