Rozwiązania do generowania dynamicznego javascript / CSS

15

Powiedzmy, że musisz wygenerować kod JavaScript lub CSS, który zależy od bieżącego kontekstu.

Na przykład masz formularz na stronie głównej, który uruchamia żądanie ajax przy wysyłaniu, i inny formularz na pojedynczej stronie. Lub w przypadku CSS, chcesz stworzyć motyw, który pozwoli użytkownikom budować własny układ, zmieniać kolory itp.

Rozwiązania, które do tej pory widzę:

  1. Dołącz kod w sekcji nagłówka dokumentu (lub na końcu w przypadku JS)

  2. Wykonaj specjalne żądanie, które wyświetli kod, na przykład site.com?get_assets . Jest to powolne, ponieważ WP ładuje się dwukrotnie.

  3. Przechowuj go w plikach tymczasowych przez określony czas i ładuj stamtąd. Niezbyt wiarygodny w przypadku publicznych motywów lub wtyczek.

  4. Tylko JavaScript - ustaw go jako statyczny, umieszczając go w normalnym pliku, który jest ładowany za każdym razem. W takim przypadku Twój kod będzie obsługiwał każdą sytuację

Czy znasz innych? W którą stronę byś poszedł?

onetrickpony
źródło
Jednym z problemów, które napotkałem w rozwiązaniu 1, jest buforowanie przez przeglądarkę, kod nie jest odświeżany po przeładowaniu strony.
Aurovrata

Odpowiedzi:

9

Jedna dodatkowa opcja, w zależności od rodzaju parametrów, które należy przekazać. Nazwijmy to (2a). Możesz także tworzyć skrypty PHP, które generują dane generowane dynamicznie text/csslub text/javascriptraczej text/htmli dostarczać im danych, których potrzebują, używając parametrów GET zamiast ładować WordPress. Oczywiście działa to tylko wtedy, gdy trzeba przekazać stosunkowo niewielką liczbę stosunkowo zwartych parametrów. Powiedzmy na przykład, że musisz podać tylko adres URL wpisu lub katalog pliku lub podobny, możesz zrobić coś takiego:

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

W fancy-js.php:

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

itp.

Ale to pozwala tylko na dostęp do danych przekazywanych bezpośrednio w parametrach GET; i zadziała tylko wtedy, gdy liczba rzeczy, które musisz przekazać, jest stosunkowo niewielka, a reprezentacja tych rzeczy stosunkowo niewielka. (Zasadniczo garść wartości łańcuchowych lub liczbowych - nazwa użytkownika, powiedzmy lub katalog; nie lista wszystkich ostatnich postów użytkownika lub coś podobnego.)

Co do tego, która z tych opcji jest najlepsza - nie wiem; zależy to od przypadku użycia. Opcja (1) ma tę zaletę, że jest prosta i wyraźnie umożliwia dostęp do dowolnych danych WordPress, których możesz potrzebować, bez pogorszenia wydajności w przypadku dwukrotnego ładowania WordPress. Jest prawie na pewno to, co powinieneś zrobić, chyba że masz silny powód, aby tego nie robić (np. Ze względu na rozmiar arkusza stylów lub skryptu, którego musisz użyć).

Jeśli rozmiar staje się wystarczająco duży, aby spowodować problem z wagą jednej strony, możesz wypróbować (2) lub (2a).

Albo też - prawdopodobnie jest to lepszy pomysł - możesz spróbować oddzielić części skryptu lub arkusza stylów, które faktycznie wykorzystują dane dynamiczne od części, które można określić statycznie. Powiedzmy, że masz arkusz stylów, który należy przekazać do katalogu z WordPress, aby ustawić parametr tła dla elementu # my-fancy. Możesz to wszystko umieścić w elemencie 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>

Ale dlaczego miałbyś to robić? Jest tylko jedna linia, która zależy od danych z WordPress. Lepiej rozdzielić tylko linie zależne od WordPressa:

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

Umieść wszystko inne w statycznym arkuszu stylów, który ładujesz za pomocą standardowego elementu łącza (style.css lub cokolwiek innego):

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

I niech kaskada wykona pracę.

To samo dotyczy JavaScript: zamiast tego:

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

Zamiast tego umieść coś takiego w elemencie 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>

A następnie upuść resztę do statycznego pliku JavaScript, przepisując my_huge_function () i my_other_function (), aby skorzystać z globalnych WordPressPostData.url i WordPressPostData.author.

40 KB CSS lub 40 KB JS można prawie zawsze podzielić na <1 KB, który faktycznie zależy od danych dynamicznych, a resztę można określić w statycznym pliku zewnętrznym, a następnie zrekombinować za pomocą kaskady (dla CSS) lub globalnie dostępnej zmienne (globalne, elementy DOM lub cokolwiek innego preferowanego przedziału dla JS).

radgeek
źródło
Genialna odpowiedź!
scribu
2
Tylko mały dodatek: w przypadku JS możemy użyć wp_localize_sciprt, aby dodać zmienne dynamiczne.
Anh Tran
6

Dynamiczny przypadek CSS jest dość prosty.

Wystarczy utworzyć funkcję, która wyprowadza dynamiczne definicje CSS wewnątrz <style type="text/css"></style>tagów, a następnie podpiąć tę funkcję wp_print_styles. na przykład

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

Lub, powiedzmy, że masz wstępnie skonfigurowane schematy kolorów; możesz przekształcić odpowiedni arkusz stylów zgodnie z bieżącymi ustawieniami użytkownika:

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

Zauważ, że w tym przypadku funkcja zaczepia się wp_enqueue_scripts, ponieważ WordPress nie ma wp_enqueue_styleszaczepu akcji.

Chip Bennett
źródło
1
tak samo jak 1). To właśnie robię teraz, ale jeśli masz 40 KB CSS, dostajesz obszerny dokument HTML
onetrickpony
1
Ale te 40 000 CSS musi być gdzieś wyprowadzone , prawda? I zdecydowanie taki sam jak numer 1, ale to właściwy sposób na wstrzyknięcie dynamicznego CSS w WordPress. :)
Chip Bennett
2

Myślałem o tym teraz. Twoje pytanie każe mi wrócić do tego. Nie jestem pewien, czy to dobry pomysł, czy nie, dlatego chciałbym, aby eksperci komentowali to.

Co zrobić, jeśli mam napisać pliku JavaScript / CSS poprzez php podczas zapisywania administratora danych. Będzie to jednorazowy zapis, dopóki użytkownik nie zmieni układu ponownie (który użytkownik może nie robić zbyt często). W ten sposób uzyskujemy dostęp do bazy danych ustawień użytkownika tylko raz, gdy użytkownik zapisuje dane.

Po zapisaniu pliku będą to zwykłe pliki javascript / css, więc nie musimy wywoływać bazy danych przy każdym ładowaniu kompozycji.

Jedno pytanie, na które należy odpowiedzieć: co się stanie, gdy użytkownik spróbuje uzyskać dostęp do strony w momencie, gdy php pisze plik?

Powiedz mi co myślisz.

Sisir
źródło
Jeśli wygenerujesz te pliki w wp-content/uploads(jedynym katalogu, w którym można zapisywać z kodu WP), może to być realne podejście. Myślę, że nawet WP Core używa tej techniki dla jednego pliku js.
scribu
Wadą jest to, że nie jest tak naprawdę dynamiczny, tzn. Jest taki sam dla wszystkich na wszystkich stronach. Dla każdej odmiany musisz wygenerować nowy plik. Jak wspomniałeś, nadal jest to dobre podejście do opcji motywu / wtyczek.
scribu
@scribu: tak, to prawda. może to być bałagan dla czegoś takiego. jeśli damy użytkownikom niestandardową stronę profilu i będziemy musieli zapisywać pliki dla każdego z nich. Ale może to być dobre podejście do czegoś takiego, jak jeśli wykonujemy wizualny kreator stron internetowych (przeciągnij i upuść), w którym użytkownik zmienia kolory i dodaje różne efekty (jak na to pytanie) itp. I może być łączony z WPMU;)
Sisir
1

W przypadku małych fragmentów skryptów, których możesz nie chcieć umieszczać w osobnym pliku, na przykład ponieważ są one generowane dynamicznie, WordPress 4.5 i dalsze oferty wp_add_inline_script. Ta funkcja zasadniczo blokuje skrypt na innym skrypcie. Załóżmy na przykład, że opracowujesz motyw i chcesz, aby Twój klient mógł wstawiać własne skrypty (takie jak Google Analytics lub AddThis) na stronie opcji. Przykład .

W przypadku stylów istnieje to wp_add_inline_style, co w zasadzie działa tak samo. Użyłbyś go, na przykład, do przeglądania wszystkich modów dostosowywania i zbierania ich w ciągu o nazwie $all_mods, który następnie dodajesz w ten sposób do głównego arkusza stylów:

if (!empty($all_mods)) wp_add_inline_style ('main-style', $all_mods);
cjbj
źródło
-2

Utwórz dynamiczny plik JS.php i wprowadź do niego ważne zmienne query_vars. Te zmienne $_GETpomogą plikowi określić kontekst, w którym możesz buforować i używać readfile()dla przyszłych żądań ... robić cokolwiek.

Upewnij się tylko, że plik ładuje się wp-load.phpprzed wszystkim innym, aby mieć dostęp do funkcji WP. Użyj ścieżki względnej do bieżącego folderu (dirname(__FILE__))lub po prostu digg malejąco w strukturze folderów, aby zlokalizować wp-load.phpniezależnie od rozmieszczenia wtyczek.

Kod do wyszukiwania wp-load.php z dowolnego miejsca

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

Pozdrawiam, Scribu!

PS : W przypadku skomplikowanych struktur, w których foldery nie mają normalnej struktury zmniejszającej WP, wtyczki nadrzędne mogą udostępniać informacje bezpośrednio dostępnym plikom. Wtyczka nadrzędna, która jest dostarczana z dynamicznym plikiem PHP, który renderuje CSS / JS, może zapisać do pliku, realpath()z którego wp-load.phpmogą korzystać również pliki autonomiczne. Byłby to problem dla 0,1% użytkowników WP. Myślę, że ci, którzy przenoszą foldery i nie przestrzegają normalnej struktury, wiedzą, co robią, i prawdopodobnie mogą wtyczki PIMP, które trzeba ładować wp-load.phpbezpośrednio.

EarnestoDev
źródło
Uroczy! Hejterzy, dołączcie wyjaśnienia. Oświeć mnie. Dzięki;) xoxo
EarnestoDev
wp-load.phpDołączanie z pliku motywu lub wtyczki jest złą praktyką , ponieważ katalogi wp-contenti / lub pluginskatalogi mogą znajdować się w dowolnym miejscu względem katalogu głównego WP. Pamiętaj WP_CONTENT_DIR i WP_PLUGINS_DIR.
scribu
1
@scribu A samodzielny plik może współpracować z nadrzędną wtyczką. Wtyczka nadrzędna może przechowywać plik wp-load.php w folderze, w którym się znajduje, a dynamiczny generator js może go odczytać z tego miejsca. Proste ...
EarnestoDev,
1
Tak, podejście wtyczki nadrzędnej może działać. Napisz to w swojej odpowiedzi, a usunę mój głos negatywny. PS: Ta strona jest w języku angielskim; możesz mieć problemy, jeśli będziesz nadal zostawiać uwagi w języku rumuńskim.
scribu
5
Wytnij nastawienie. Ręczne obciążenie rdzenia jest opłacalną techniką, ale w większości przypadków nie jest dobrym pierwszym wyborem. Nikt nie wątpi, że możesz sprawić, by działało. Głosy dotyczą jakości odpowiedzi, a nie mózgu.
Rarst