Lösungen zur Generierung von dynamischem Javascript / CSS

15

Angenommen, Sie müssen Javascript oder CSS-Code generieren, der vom aktuellen Kontext abhängt.

Zum Beispiel haben Sie ein Formular auf der Homepage, das eine Ajax-Anfrage beim Senden auslöst, und ein anderes Formular auf der einzelnen Seite. Oder im Fall von CSS möchten Sie ein Thema erstellen, mit dem Benutzer ihr eigenes Layout erstellen, Farben ändern usw. können.

Bisherige Lösungen:

  1. Fügen Sie den Code in den Kopfteil des Dokuments ein (oder am Ende bei JS)

  2. Führen Sie eine spezielle Anforderung durch, die den Code ausgibt, z . B. site.com?get_assets . Dies ist langsam, da WP zweimal geladen wird.

  3. Speichern Sie es für eine bestimmte Zeit in temporären Dateien und laden Sie es von dort. Nicht sehr zuverlässig für öffentliche Themen oder Plugins.

  4. Nur Javascript - machen Sie es statisch, indem Sie es in eine normale Datei packen, die jedes Mal geladen wird. In diesem Fall müssten Sie Ihren Code in jede Situation bringen

Kennst du andere Welchen Weg würdest du gehen?

ein Trickpony
quelle
Ein Problem, auf das ich bei Lösung 1 gestoßen bin, ist das Zwischenspeichern durch den Browser. Der Code wird beim Neuladen der Seite nicht aktualisiert.
Aurovrata

Antworten:

9

Eine zusätzliche Option, abhängig von der Art der Parameter, die Sie übergeben müssen. Nennen wir es (2a). Sie können auch PHP-Skripte erstellen, die dynamisch generiert text/cssoder text/javascriptnicht generiert werden text/html, und ihnen die Daten bereitstellen, die sie mithilfe von GET-Parametern benötigen, anstatt WordPress zu laden. Dies funktioniert natürlich nur, wenn Sie eine relativ kleine Anzahl relativ kompakter Parameter übergeben müssen. Angenommen, Sie müssen nur die URL eines Posts oder das Verzeichnis einer Datei o.ä. übergeben, dann können Sie Folgendes tun:

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

In fancy-js.php:

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

etc.

Auf diese Weise können Sie jedoch nur auf die Daten zugreifen, die direkt in den GET-Parametern übergeben wurden. und es wird nur funktionieren, wenn die Anzahl der Dinge, die Sie übergeben müssen, relativ gering und die Darstellung dieser Dinge relativ kompakt ist. (Im Grunde genommen eine Handvoll Zeichenfolgen oder numerische Werte - ein Benutzername, etwa oder ein Verzeichnis; keine Liste aller letzten Beiträge eines Benutzers oder ähnliches.)

Welche dieser Optionen die beste ist - ich weiß es nicht; Das hängt von Ihrem Anwendungsfall ab. Option (1) hat den Vorteil, einfach zu sein und Ihnen den Zugriff auf alle WordPress-Daten zu ermöglichen, die Sie möglicherweise benötigen, ohne dass die Leistung durch zweimaliges Laden von WordPress beeinträchtigt wird. Es ist fast sicher, was Sie tun sollten, es sei denn, Sie haben einen starken Grund, dies nicht zu tun (z. B. aufgrund der Größe des Stylesheets oder Skripts, das Sie verwenden müssen).

Wenn die Größe groß genug ist, um ein Problem in Bezug auf das Gewicht Ihrer einen Seite zu verursachen, können Sie (2) oder (2a) ausprobieren.

Andernfalls - dies ist wahrscheinlich die bessere Idee - können Sie versuchen, die Teile des Skripts oder des Stylesheets, die die dynamischen Daten tatsächlich verwenden, von den Teilen zu trennen, die statisch angegeben werden können. Angenommen, Sie haben ein Stylesheet, dem ein Verzeichnis von WordPress übergeben werden muss, um einen Hintergrundparameter für das # my-fancy-Element festzulegen. Sie können dies alles in das head-Element einfügen:

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

Aber warum sollten Sie das tun müssen? Es gibt hier nur eine Zeile, die von Daten aus WordPress abhängt. Besser nur die Zeilen aufteilen, die von WordPress abhängen:

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

Fügen Sie alles andere in ein statisches Stylesheet ein, das Sie mit einem Standardlinkelement (style.css oder was auch immer) laden:

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

Und lassen Sie die Kaskade die Arbeit machen.

Das gleiche gilt für JavaScript: anstatt dies zu tun:

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

Fügen Sie stattdessen so etwas in das head-Element ein:

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

Und dann legen Sie den Rest in einer statischen JavaScript-Datei ab und schreiben die Funktionen my_huge_function () und my_other_function () neu, um die globalen Elemente WordPressPostData.url und WordPressPostData.author zu verwenden.

40 KB CSS oder 40 KB JS können fast immer in <1 KB aufgeteilt werden, was tatsächlich von dynamischen Daten abhängt. Der Rest kann in einer statischen externen Datei angegeben und dann mithilfe der Kaskade (für CSS) oder mit globalem Zugriff neu kombiniert werden Variablen (Globals, DOM-Elemente oder was auch immer Sie bevorzugen, für JS).

radgeek
quelle
Geniale Antwort!
Scribu
2
Nur ein kleiner Zusatz: Im Falle von JS können wir wp_localize_sciprt verwenden , um dynamische Variablen hinzuzufügen.
Anh Tran
6

Der dynamische CSS-Fall ist ziemlich einfach.

Erstellen Sie einfach eine Funktion, die die dynamischen CSS-Definitionen in <style type="text/css"></style>Tags ausgibt , und binden Sie diese Funktion ein wp_print_styles. z.B

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

Angenommen, Sie haben Farbschemata vorkonfiguriert. Sie können das entsprechende Stylesheet entsprechend der aktuellen Benutzereinstellung einreihen:

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

Beachten Sie, dass sich in diesem Fall die Funktion einhakt wp_enqueue_scripts, da WordPress keinen wp_enqueue_stylesAktions-Hook hat.

Chip Bennett
quelle
1
das gleiche wie 1). Dies ist, was ich jetzt mache, aber wenn Sie 40 KB CSS haben, erhalten Sie ein
umfangreiches
1
Aber diese 40K CSS müssen irgendwo ausgegeben werden , oder? Und definitiv das Gleiche wie Nummer 1, aber es ist der richtige Weg , um dynamisches CSS in WordPress einzufügen. :)
Chip Bennett
2

Ich dachte das schon eine Weile. Ihre Frage lässt mich darauf zurückkommen. Ich bin mir nicht sicher, ob es eine gute Idee ist oder nicht, daher möchte ich Experten-Kommentare dazu.

Was ist, wenn ich die Javascript / CSS-Datei über PHP schreibe, wenn der Administrator die Daten speichert ? Es wird einmalig geschrieben, bis der Benutzer das Layout erneut ändert (was der Benutzer möglicherweise nicht zu oft tut). Auf diese Weise greifen wir nur einmal auf die Datenbank für die Benutzereinstellungen zu, wenn der Benutzer Daten speichert.

Nach dem Schreiben der Datei handelt es sich um reguläre Javascript- / CSS-Dateien, sodass wir die Datenbank nicht jedes Mal aufrufen müssen, wenn das Thema geladen wird.

Eine Frage, die beantwortet werden muss: Was passiert, wenn ein Besucher versucht, auf die Site zuzugreifen, sobald PHP die Datei schreibt?

Lass mich wissen was du denkst.

Sisir
quelle
Wenn Sie diese Dateien in generieren wp-content/uploads(dem einzigen Verzeichnis, das garantiert aus WP-Code beschreibbar ist), könnte dies ein praktikabler Ansatz sein. Ich denke, dass sogar WP Core diese Technik für eine js-Datei verwendet.
Scribu
Der Nachteil ist, dass es nicht wirklich dynamisch ist, dh es ist für alle auf allen Seiten gleich. Für jede Variation müssten Sie eine neue Datei generieren. Es ist immer noch ein guter Ansatz für Theme / Plugin-Optionen, wie Sie erwähnt haben.
Scribu
@scribu: Ja, es ist wahr. Es kann ein Durcheinander für so etwas sein. Wenn wir Benutzern eine angepasste Profilseite geben und Dateien für jede einzelne von ihnen schreiben müssen. Aber es könnte ein guter Ansatz sein, wenn wir einen visuellen Website-Maker (Drag & Drop) machen, bei dem der Benutzer die Farben ändert und verschiedene Effekte hinzufügt (wie bei dieser Frage) usw. und mit WPMU kombiniert werden kann;)
Sisir
1

Für kleine Teile von Skripten, die Sie möglicherweise nicht in eine separate Datei aufnehmen möchten, weil sie beispielsweise dynamisch generiert werden, bietet sich WordPress 4.5 und weitere an wp_add_inline_script. Diese Funktion speichert das Skript grundsätzlich in einem anderen Skript. Angenommen, Sie entwickeln ein Thema und möchten, dass Ihr Kunde seine eigenen Skripts (wie Google Analytics oder AddThis) über die Optionsseite einfügen kann. Beispiel .

Für Styles gibt es wp_add_inline_style, die grundsätzlich gleich funktionieren. Sie würden es zum Beispiel verwenden, um alle Ihre Customizer-Mods zu durchlaufen und sie in einem String mit dem Namen zusammenzufassen $all_mods, den Sie dann wie folgt zu Ihrem Haupt-Stylesheet hinzufügen würden:

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

Erstellen Sie eine dynamische JS.php-Datei und geben Sie ihr wichtige query_vars. Diese Variablen $_GEThelfen der Datei dabei, den Kontext zu bestimmen, und Sie können sie zwischenspeichern und readfile()für zukünftige Anforderungen verwenden.

Stellen Sie einfach sicher, dass die Datei wp-load.phpvor allem anderen geladen wird, damit Sie Zugriff auf WP-Funktionen haben. Verwenden Sie den relativen Pfad zum aktuellen Ordner (dirname(__FILE__))oder digg in absteigender Reihenfolge in der Ordnerstruktur, um wp-load.phpunabhängig von der Platzierung des Plugins zu suchen.

Code, um wp-load.php von überall zu suchen

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

Prost, Scribu!

PS : Bei komplizierten Strukturen, bei denen Ordner nicht der normalen WP-Dekrementierungsstruktur folgen, können übergeordnete Plug-ins Informationen mit direkt zugreifbaren Dateien austauschen. Ein übergeordnetes Plugin, das mit einer dynamischen PHP-Datei geliefert wird, die CSS / JS rendert, kann in eine Datei schreiben, die realpath()von der wp-load.phpund der Standalone-Datei verwendet werden kann. Dies wäre ein Problem für 0,1% der WP-Benutzer. Ich denke, diejenigen, die Ordner verschieben und nicht der normalen Struktur folgen, wissen, was sie tun, und können wahrscheinlich PIMP-Plugins, die wp-load.phpdirekt geladen werden müssen.

EarnestoDev
quelle
Süß! Hasser, bitte Erklärungen anhängen. Kläre mich auf. Danke;) xoxo
EarnestoDev
Es ist wp-load.phpkeine gute Praxis, ein Theme oder eine Plugin-Datei einzubeziehen, da sich das Verzeichnis wp-contentund / oder das pluginsVerzeichnis an einer beliebigen Stelle relativ zum WP-Stammverzeichnis befinden können. Denken Sie an WP_CONTENT_DIR und WP_PLUGINS_DIR.
Scribu
1
@scribu Und die eigenständige Datei kann mit einem übergeordneten Plugin zusammenarbeiten. Das übergeordnete Plugin kann die Datei wp-load.php in dem Ordner speichern, in dem sie sich befindet, und der dynamische js-Generator kann sie von dort aus lesen. Einfach ...
EarnestoDev
1
Ja, der Ansatz des übergeordneten Plugins könnte funktionieren. Schreiben Sie es in Ihre Antwort und ich werde meine Ablehnung entfernen. PS: Diese Seite ist in Englisch; Sie könnten Probleme haben, wenn Sie weiterhin Anmerkungen auf Rumänisch hinterlassen.
Scribu
5
Schneiden Sie die Haltung. Manuelle Kernbelastung ist eine praktikable Technik, aber für die meisten Dinge keine gute erste Wahl. Niemand zweifelt daran, dass Sie es zum Laufen bringen können. Bei Abstimmungen geht es um die Qualität Ihrer Antwort, nicht um Ihr Gehirn.
Rarst