Solutions pour générer du javascript / CSS dynamique

15

Disons que vous devez générer du code javascript ou CSS qui dépend du contexte actuel.

Par exemple, vous avez un formulaire sur la page d'accueil qui déclenche une demande ajax lors de la soumission, et un autre formulaire sur la page unique. Ou dans le cas de CSS, vous souhaitez créer un thème qui permet à ses utilisateurs de créer leur propre mise en page, de changer les couleurs, etc.

Solutions que je vois jusqu'à présent:

  1. Inclure le code dans la section tête du document (ou à la fin en cas de JS)

  2. Faites une demande spéciale qui génère le code, comme site.com?get_assets . C'est lent car WP est chargé deux fois.

  3. Stockez-le dans des fichiers temporaires pendant un certain temps et chargez-le à partir de là. Pas très fiable pour les thèmes ou plugins publics.

  4. Javascript uniquement - rendez-le statique en le plaçant dans un fichier normal qui est chargé à chaque fois. Dans ce cas, vous devrez faire en sorte que votre code gère toute situation

Connaissez-vous les autres? Dans quelle direction iriez-vous?

onetrickpony
la source
un problème que j'ai rencontré avec la solution 1 est la mise en cache par le navigateur, le code n'est pas actualisé lors du rechargement de la page.
Aurovrata

Réponses:

9

Une option supplémentaire, selon le type de paramètres que vous devez transmettre. Appelons-le (2a). Vous pouvez également créer des scripts PHP qui génèrent dynamiquement text/cssou text/javascriptplutôt text/html, et leur fournir les données dont ils ont besoin en utilisant les paramètres GET plutôt qu'en chargeant WordPress. Bien sûr, cela ne fonctionne que si vous devez transmettre un nombre relativement petit de paramètres relativement compacts. Ainsi, par exemple, supposons que vous ne deviez transmettre que l'URL d'une publication ou le répertoire d'un fichier ou similaire, vous pouvez faire quelque chose comme ceci:

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

Dans fancy-js.php:

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

etc.

Mais cela vous permet uniquement d'accéder aux données directement transmises dans les paramètres GET; et cela ne fonctionnera que si le nombre de choses que vous devez transmettre est relativement petit et la représentation de ces choses relativement compacte. (Fondamentalement, une poignée de chaînes ou de valeurs numériques - un nom d'utilisateur, par exemple, ou un répertoire; pas une liste de tous les messages récents d'un utilisateur ou quelque chose comme ça.)

Quant à savoir laquelle de ces options est la meilleure - je ne sais pas; cela dépend de votre cas d'utilisation. L'option (1) a le mérite d'être simple et de vous permettre clairement d'accéder à toutes les données WordPress dont vous pourriez avoir besoin, sans les performances de chargement de WordPress deux fois. C'est presque certainement ce que vous devez faire, sauf si vous avez une bonne raison de ne pas le faire (par exemple, en raison de la taille de la feuille de style ou du script que vous devez utiliser).

Si la taille devient suffisamment grande pour causer un problème en termes de poids de votre page, vous pouvez essayer (2) ou (2a).

Ou bien - c'est probablement la meilleure idée - vous pouvez essayer de séparer les parties du script ou de la feuille de style qui utilisent réellement les données dynamiques des parties qui peuvent être spécifiées statiquement. Ssay vous avez une feuille de style qui doit passer un répertoire de WordPress afin de définir un paramètre d'arrière-plan pour l'élément # my-fancy. Vous pouvez mettre tout cela dans l'élément 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>

Mais pourquoi auriez-vous besoin de faire cela? Il n'y a qu'une seule ligne ici qui dépend des données de WordPress. Mieux vaut ne séparer que les lignes qui dépendent de WordPress:

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

Mettez tout le reste dans une feuille de style statique que vous chargez avec un élément de lien standard (style.css ou autre):

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

Et laissez la cascade faire le travail.

Il en va de même pour JavaScript: plutôt que de faire ceci:

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

Au lieu de cela, mettez quelque chose comme ça dans l'élément 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>

Ensuite, déposez le reste dans un fichier JavaScript statique, réécrivant my_huge_function () et my_other_function () pour utiliser les globaux WordPressPostData.url et WordPressPostData.author.

40K de CSS ou 40K de JS peuvent presque toujours être divisés en <1K qui dépend en fait des données dynamiques, et le reste, qui peut être spécifié dans un fichier externe statique et ensuite recombiné en utilisant soit la cascade (pour CSS) ou globalement accessible variables (globales, éléments DOM, ou tout autre cubby-hole que vous préférez, pour JS).

radgeek
la source
Brillante réponse!
scribu
2
Juste un petit ajout: dans le cas de JS, nous pouvons utiliser wp_localize_sciprt pour ajouter des variables dynamiques.
Anh Tran
6

Le cas CSS dynamique est assez simple.

Créez simplement une fonction qui génère les définitions CSS dynamiques à l'intérieur des <style type="text/css"></style>balises, puis connectez cette fonction à wp_print_styles. par exemple

<?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, disons que vous avez des schémas de couleurs préconfigurés; vous pouvez mettre en file d'attente la feuille de style appropriée en fonction du paramètre utilisateur actuel:

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

Notez que, dans ce cas, la fonction s'accroche wp_enqueue_scripts, puisque WordPress n'a pas de wp_enqueue_styleshook d'action.

Chip Bennett
la source
1
comme 1). C'est ce que je fais maintenant, mais si vous avez comme 40K de CSS, vous obtenez un document HTML volumineux
onetrickpony
1
Mais ces 40K de CSS doivent être sortis quelque part , non? Et, certainement la même chose que # 1, mais c'est la bonne façon d'injecter du CSS dynamique dans WordPress. :)
Chip Bennett
2

Je pensais ça depuis un moment maintenant. Votre question me fait y revenir. Je ne suis pas sûr que ce soit une bonne idée ou non, alors j'aimerais que les experts commentent cela.

Et qu'est-ce qui se passerait si j'écris le javascript / fichier css via php lors de l' enregistrement des données d' administration. Ce sera une écriture unique jusqu'à ce que l'utilisateur modifie à nouveau la mise en page (ce que l'utilisateur ne peut pas faire trop souvent). De cette façon, nous accédons à la base de données pour les paramètres utilisateur une seule fois lorsque l'utilisateur enregistre des données.

Après avoir écrit le fichier, ce sera un fichier javascript / css normal, nous n'avons donc pas besoin d'appeler la base de données à chaque chargement du thème.

Une question à laquelle il faut répondre: que se passera-t-il lorsqu'un visiteur tentera d'accéder au site à l'instant où php écrit le fichier?

Laissez-moi savoir ce que vous pensez.

Sisir
la source
Si vous générez ces fichiers dans wp-content/uploads(le seul répertoire garanti être accessible en écriture à partir du code WP), cela pourrait être une approche viable. Je pense que même WP Core utilise cette technique pour un fichier js.
scribu
L'inconvénient est que ce n'est pas vraiment dynamique, c'est-à-dire que c'est la même chose pour tout le monde sur toutes les pages. Pour chaque variante, vous devrez générer un nouveau fichier. C'est toujours une bonne approche pour les options de thème / plugin, comme vous l'avez mentionné.
scribu
@scribu: oui c'est vrai. cela peut être un gâchis pour quelque chose comme. si nous donnons aux utilisateurs une page de profil personnalisée et devons écrire des fichiers chacun d'eux. Mais cela pourrait être une bonne approche pour quelque chose comme si nous faisons un créateur de site Web visuel (glisser-déposer) où l'utilisateur change les couleurs et ajoute divers effets (à partir de cette question) etc. et peut être combiné avec WPMU;)
Sisir
1

Pour les petits morceaux de scripts, que vous ne voudrez peut-être pas inclure dans un fichier séparé, par exemple parce qu'ils sont générés dynamiquement, WordPress 4.5 et d'autres offres wp_add_inline_script. Cette fonction verrouille essentiellement le script dans un autre script. Disons, par exemple, que vous développez un thème et que vous souhaitez que votre client puisse insérer ses propres scripts (comme Google Analytics ou AddThis) via la page d'options. Exemple .

Pour les styles, il y a wp_add_inline_style, qui fonctionne essentiellement de la même manière. Vous l'utiliseriez, par exemple, pour parcourir tous vos mods de personnalisation et les rassembler dans une chaîne appelée $all_mods, que vous ajouteriez ensuite comme ceci à votre feuille de style principale:

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

Créez un fichier JS.php dynamique et alimentez-le en important query_vars. Ces variables $_GETaideront le fichier à déterminer le contexte et vous pourrez y mettre en cache et utiliserreadfile() pour de futures requêtes ... faites tout.

Assurez-vous simplement que le fichier se charge wp-load.phpavant toute autre chose, afin d'avoir accès aux fonctions WP. Utilisez le chemin relatif vers le dossier en cours (dirname(__FILE__))ou simplement digg descendant dans la structure du dossier pour localiserwp-load.php indépendamment du placement du plugin.

Code pour rechercher wp-load.php de n'importe où

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

À la vôtre, Scribu!

PS : Pour les structures compliquées où les dossiers ne suivent pas la structure décrémentielle WP normale, les plugins parents peuvent partager des informations avec des fichiers directement accessibles. Un plugin parent fourni avec un fichier PHP dynamique qui rend CSS / JS peut écrire dans un fichier realpath()le wp-load.phpet le fichier autonome peut l'utiliser. Ce serait un problème pour 0,1% des utilisateurs de WP. Je pense que ceux qui déplacent des dossiers et ne suivent pas la structure normale savent ce qu'ils font et peuvent probablement des plugins PIMP qui doivent être chargés wp-load.phpdirectement.

EarnestoDev
la source
Mignonne! Haters, veuillez ajouter des explications. Éclaire-moi. Merci;) xoxo
EarnestoDev
C'est une mauvaise pratique d'inclure à wp-load.phppartir d'un thème ou d'un fichier de plugin, car les répertoires wp-contentet / ou pluginspeuvent être n'importe où par rapport au répertoire racine WP. N'oubliez pas WP_CONTENT_DIR et WP_PLUGINS_DIR.
scribu
1
@scribu Et le fichier autonome peut collaborer avec un plugin parent. Le plugin parent peut stocker le wp-load.php dans le dossier où il se trouve et le générateur dynamique js peut le lire à partir de là. Simple ...
EarnestoDev
1
Oui, l'approche du plugin parent pourrait fonctionner. Écrivez-le dans votre réponse et je supprimerai mon downvote. PS: Ce site est en anglais; vous pourriez avoir des problèmes si vous continuez à laisser des remarques en roumain.
scribu
5
Coupez l'attitude. La charge manuelle du cœur est une technique viable, mais loin d'être un bon premier choix pour la plupart des choses. Personne ne doute que vous pouvez le faire fonctionner. Les votes concernent la qualité de votre réponse, pas votre cerveau.
Rarst