Решения для генерации динамического JavaScript / CSS

15

Допустим, вам нужно сгенерировать JavaScript или код CSS, который зависит от текущего контекста.

Например, у вас есть форма на главной странице, которая запускает ajax-запрос при отправке, и другая форма на одной странице. Или, в случае с CSS, вы хотите создать тему, которая позволит пользователям создавать собственные макеты, менять цвета и т. Д.

Решения, которые я вижу до сих пор:

  1. Включите код в раздел заголовка документа (или в конце в случае JS)

  2. Сделайте специальный запрос, который выводит код, например site.com?get_assets . Это медленно, потому что WP загружается дважды.

  3. Сохраните его во временных файлах в течение определенного времени и загрузите оттуда. Не очень надежно для публичных тем или плагинов.

  4. Только для Javascript - сделайте его статичным, поместив его в обычный файл, который загружается каждый раз. В этом случае вам придется заставить свой код обрабатывать любую ситуацию

Ты знаешь других? По какому пути вы пойдете?

onetrickpony
источник
Одна проблема, с которой я столкнулся при решении 1, - это кэширование браузером, при перезагрузке страницы код не обновляется.
Ауроврата,

Ответы:

9

Одна дополнительная опция, в зависимости от типа параметров, которые вам нужно передать. Давайте назовем это (2a). Вы также можете создавать PHP-скрипты, которые выводят динамически сгенерированные text/cssили text/javascriptвместо них text/html, и предоставлять им необходимые данные, используя параметры GET, а не загружая WordPress. Конечно, это работает, только если вам нужно передать относительно небольшое количество относительно компактных параметров. Так, например, скажем, вам нужно передать только URL-адрес поста или директории файла или чего-то подобного, вы можете сделать что-то вроде этого:

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

В fancy-js.php:

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

и т.п.

Но это только позволяет вам получить доступ к данным, непосредственно переданным в параметрах GET; и это будет работать только в том случае, если количество вещей, которые вам нужно передать, относительно мало, а представление этих вещей относительно компактно. (В основном горстка строковых или числовых значений - имя пользователя, скажем, или каталог; не список всех последних сообщений пользователя или что-то в этом роде.)

Что касается того, какой из этих вариантов является лучшим - я не знаю; это зависит от вашего варианта использования. Вариант (1) имеет преимущество простоты и однозначного предоставления вам доступа к любым данным WordPress, которые вам могут понадобиться, без снижения производительности при двойной загрузке WordPress. Это почти наверняка то, что вы должны делать, если у вас нет веских причин не делать этого (например, из-за размера таблицы стилей или сценария, которые вам нужно использовать).

Если размер становится достаточно большим, чтобы вызвать проблемы с точки зрения веса одной страницы, то вы можете попробовать (2) или (2a).

Или - возможно, это лучшая идея - вы можете попытаться отделить части скрипта или таблицы стилей, которые фактически используют динамические данные, от частей, которые могут быть определены статически. Скажем, у вас есть таблица стилей, которой нужно передать каталог из WordPress, чтобы установить параметр фона для элемента # my-fancy. Вы можете поместить все это в элемент 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>

Но зачем вам это делать? Здесь есть только одна строка, которая зависит от данных из WordPress. Лучше выделить только те строки, которые зависят от WordPress:

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

Поместите все остальное в статическую таблицу стилей, в которую вы загружаете стандартный элемент ссылки (style.css или любой другой):

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

И пусть каскад сделает всю работу.

То же самое касается JavaScript: вместо того, чтобы делать это:

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

Вместо этого поместите что-то вроде этого в элемент 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>

А затем поместите остальные в статический файл JavaScript, переписав my_huge_function () и my_other_function (), чтобы использовать глобальные переменные WordPressPostData.url и WordPressPostData.author.

40 КБ CSS или 40 КБ JS почти всегда можно разбить на <1 КБ, что на самом деле зависит от динамических данных, а остальные - могут быть указаны в статическом внешнем файле и затем рекомбинированы с использованием каскада (для CSS) или глобально доступного переменные (глобальные переменные, элементы DOM или любые другие предпочтительные места для JS).

radgeek
источник
Блестящий ответ!
scribu
2
Небольшое дополнение: в случае JS мы можем использовать wp_localize_sciprt для добавления динамических переменных.
Ань Чан
6

Динамический случай CSS довольно прост.

Просто создайте функцию, которая выводит динамические определения CSS внутри <style type="text/css"></style>тегов, а затем подключите эту функцию к wp_print_styles. например

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

Или, скажем, у вас есть предварительно настроенные цветовые схемы; Вы можете поставить в очередь соответствующую таблицу стилей в соответствии с текущими настройками пользователя:

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

Обратите внимание, что в этом случае функция подключается wp_enqueue_scripts, поскольку WordPress не имеет wp_enqueue_stylesловушки действий.

Чип Беннетт
источник
1
такой же как 1). Это то, что я делаю сейчас, но если у вас
около 40 КБ
1
Но эти 40K CSS должны быть где-то выведены , верно? И, безусловно, такой же, как # 1, но это верный способ внедрить динамический CSS в WordPress. :)
Чип Беннетт
2

Я думал об этом некоторое время сейчас. Ваш вопрос заставляет меня вернуться к нему. Не уверен, что это хорошая идея или нет, поэтому я хотел бы получить комментарии экспертов по этому поводу.

Что делать, если я пишу файл javascript / css через php, когда администратор сохраняет данные. Это будет однократная запись, пока пользователь не изменит макет снова (что пользователь может делать не слишком часто). Таким образом, мы получаем доступ к базе данных для пользовательских настроек только один раз, когда пользователь сохраняет данные.

После записи файла это будут обычные файлы javascript / css, поэтому нам не нужно вызывать базу данных каждый раз при загрузке темы.

Один вопрос, на который нужно ответить: что произойдет, когда посетитель попытается получить доступ к сайту в тот момент, когда php пишет файл?

Дайте мне знать, что вы думаете.

Sisir
источник
Если вы создадите эти файлы в wp-content/uploads(единственном каталоге, который гарантированно доступен для записи из кода WP), это может быть жизнеспособным подходом. Я думаю, что даже WP Core использует эту технику для одного файла js.
scribu
Недостатком является то, что он не очень динамичный, то есть он одинаков для всех на всех страницах. Для каждого варианта вам нужно будет создать новый файл. Как вы упомянули, это хороший подход к настройкам тем / плагинов.
scribu
@scribu: да, это правда. это может быть беспорядок для чего-то вроде. если мы дадим пользователям настроенную страницу профиля и должны будем записывать файлы каждый из них. Но это может быть хорошим подходом для чего-то подобного, если мы создадим визуальный веб-сайт (перетаскивание), где пользователь меняет цвета и добавляет различные эффекты (на этот вопрос) и т. Д. И может сочетаться с WPMU;)
Sisir
1

Для небольших фрагментов скриптов, которые вы, возможно, не захотите включать в отдельный файл, например, потому что они генерируются динамически, WordPress 4.5 и другие предложения wp_add_inline_script. Эта функция в основном привязывает скрипт к другому скрипту. Допустим, например, что вы разрабатываете тему и хотите, чтобы ваш клиент мог вставлять свои собственные сценарии (например, Google Analytics или AddThis) через страницу параметров. Пример .

Для стилей wp_add_inline_style, которые в основном работают одинаково. Вы могли бы использовать его, например, для циклического прохождения всех ваших модификаторов-модификаторов и собирать их в строку с именем $all_mods, которую вы затем добавили бы так в свою основную таблицу стилей:

if (!empty($all_mods)) wp_add_inline_style ('main-style', $all_mods);
cjbj
источник
-2

Создайте динамический файл JS.php и передайте ему важные query_vars. Эти переменные в $_GETфайле помогут определить контекст, и в нем вы сможете кэшировать и использовать его readfile()для будущих запросов ... делайте что угодно.

Просто убедитесь, что файл загружает wp-load.phpпрежде всего, чтобы у вас был доступ к функциям WP. Используйте относительный путь к текущей папке (dirname(__FILE__))или просто копайте по убыванию в структуре папок, чтобы найти wp-load.phpнезависимо от размещения плагина.

Код для поиска wp-load.php из любого места

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

Ура, Scribu!

PS : Для сложных структур , где папки не следуют нормальной структуре WP декрементной, родительские модули могут обмениваться информация с непосредственно доступными файлами. Родительский плагин, который поставляется с динамическим файлом PHP, который отображает CSS / JS, может записать в файл realpath()the, wp-load.phpи автономный файл может использовать это. Это будет проблемой для 0,1% пользователей WP. Я думаю, что те, кто перемещают папки и не следуют обычной структуре, знают, что они делают, и, вероятно, могут подключать плагины PIMP, которые нужно загружать wp-load.phpнапрямую.

EarnestoDev
источник
Милый! Ненавистники, пожалуйста, приложите объяснения. Просветите меня. Спасибо;) xoxo
EarnestoDev
Неправильно включать wp-load.phpиз файла темы или плагина, так как каталоги wp-contentи / или pluginsмогут находиться где угодно относительно корневого каталога WP. Помните WP_CONTENT_DIR и WP_PLUGINS_DIR.
scribu
1
@scribu А автономный файл может сотрудничать с родительским плагином. Родительский плагин может хранить wp-load.php в папке, в которой он находится, и динамический генератор js может читать его оттуда. Просто ...
EarnestoDev
1
Да, подход родительского плагина может работать. Запишите это в своем ответе, и я уберу свое понижение. PS: этот сайт на английском; у вас могут возникнуть проблемы, если вы продолжите оставлять замечания на румынском языке.
scribu
5
Отрежь отношение. Ручная загрузка ядра - жизнеспособная техника, но для большинства вещей это далеко не первый выбор. Никто не сомневается, что вы можете заставить его работать. Голоса касаются качества вашего ответа, а не вашего мозга.
Первый