ashleyg
  • 0
Учитель

Динамическое создание CSS-файлов с использованием PHP-скриптов?

  • 0

В рамках моих усилий по ускорению моих тем для моих клиентов я доставляю свой CSS через динамический файл PHP. В конце вызова, например my_theme_css.php :

Это позволяет мне добавлять заголовки Expiry в мой CSS и JavaScript следующим образом:

<?php
header("Expires: Thu, 31 Dec 2020 20:00:00 GMT");
header('Content-type: text/css');
?>

Затем я хочу разрешить пользователю добавлять свой собственный CSS, поэтому я установил следующее:

<?php
header("Expires: Thu, 31 Dec 2020 20:00:00 GMT");
header('Content-type: text/css');
?>

p{color:blue;}

/** Custom CSS **/
<?php 
if(get_theme_mod('my_custom_css') != '') {
  $my_custom_css = get_theme_mod('my_custom_css'); 
  echo $my_custom_css; 
}
?> 

Затем я добавил применимые параметры темы. Но я обнаружил, что get_theme_mod() это не работает из-за проблемы с областью действия (я думаю). Любые предложения о том, как обойти это?

Я мог бы добавить следующий код:

<?php 
if(get_theme_mod('my_custom_css') != '') {
  $my_custom_css = get_theme_mod('my_custom_css'); 
  echo $my_custom_css; 
}
?>

Внутри <style></style> тегов в заголовке, и это будет работать нормально, ожидайте, что я не хочу встроенный CSS, я хочу, чтобы он был в основном файле CSS с заголовком истечения срока действия.

Share
  1. Разве статический файл css не будет лучше для производительности? Есть также несколько хороших советов, которые я получил по аналогичному вопросу, который я задал.

    • 0
  2. Привет @Ash G:

    Я не следил на 100% за тем, где у вас конкретно возникали проблемы, поэтому я не уверен, что действительно могу ответить на ваши вопросы по пунктам, но я могу объяснить, как это сделать с нуля. И если то, что вы делаете, не намного сложнее, чем вы упомянули, это немного больше работы, чем я думаю, вы ожидали, но это все еще вполне выполнимо. И даже если я освещаю много тем, которые вы уже знаете, есть большая вероятность, что другие люди с меньшими знаниями или опытом найдут это через Google и им тоже помогут.

    Загрузить WordPress с помощью/wp-load.php

    Первое, что нам нужно сделать в вашем my_theme_css.php файле, это загрузить функции основной библиотеки WordPress. Следующая строка кода загружает /wp-load.php . Он используется $_SERVER['DOCUMENT_ROOT'] для поиска корня веб-сайта, поэтому вам не нужно беспокоиться о том, где вы храните этот файл на своем сервере; предполагая DOCUMENT_ROOT, что он установлен правильно, как всегда должно быть для WordPress, тогда это загрузит WordPress:

    <?php
    include_once("{$_SERVER['DOCUMENT_ROOT']}/wp-load.php"); 
    

    Так что это легкая часть. Далее идет сложная часть…

    PHP-скрипты должны обрабатывать всю логику кэширования

    Держу пари, здесь вы могли споткнуться, потому что я точно споткнулся, когда пытался понять, как ответить на ваш вопрос. Мы настолько привыкли к деталям кэширования, которые обрабатываются веб-сервером Apache, что забываем или даже не осознаем , что должны сами выполнять всю тяжелую работу, когда загружаем CSS или JS с PHP.

    Конечно, заголовок срока действия может быть всем, что нам нужно, когда у нас есть прокси посередине, но если запрос доходит до веб-сервера, а PHP-скрипт волей-неволей возвращает содержимое и код состояния «ОК», по сути, вы не имеют кэширования.

    Возврат «200 OK» или «304 Not Modified»

    В частности, наш файл PHP, который возвращает CSS, должен правильно реагировать на заголовки запроса, отправленные браузером. Наш PHP-скрипт должен возвращать правильный код состояния в зависимости от содержания этих заголовков. Если содержимое должно быть предоставлено, потому что это первый запрос или срок действия содержимого истек, скрипт PHP должен сгенерировать весь контент CSS и вернуться с «200 Ok».

    С другой стороны, если мы определяем на основе заголовков запросов, связанных с кешем, что клиентский браузер уже имеет последнюю версию CSS, мы не должны возвращать какой-либо CSS и вместо этого возвращать «304 Not Modified». Слишком много строк кода для этого соответственно (конечно, вы никогда не будете использовать их одну за другой, я показываю это здесь только для удобства) :

    <?php 
    header('HTTP/1.1 200 Ok');
    header('HTTP/1.1 304 Not Modified');
    

    Четыре разновидности кэширования HTTP

    Далее нам нужно рассмотреть различные способы, которыми HTTP может обрабатывать кэширование. Первое — это то, что вы упомянули; Expires :

    • Истекает : этотExpires заголовок ожидает дату в формате ( функция PHPgmdate() )'D, d M Y H:i:s' с' GMT' добавлением ( GMT означает среднее время по Гринвичу ). Теоретически, если этот заголовок обслуживается, браузер и нижестоящие прокси-серверы будут кэшироваться до тех пор, пока не пройдет указанное время, после чего он запустится. повторный запрос страницы. Это, вероятно, самый известный из кэширующих заголовков, но явно не самый предпочтительный для использования; Cache-Control лучше. Интересно, что в моем тестированииlocalhost с Safari 5.0 на Mac OS XI так и не удалось заставить браузер учитыватьExpires заголовок; это всегдаснова запросил файл (если кто-то может объяснить это, я был бы признателен). Вот пример, который вы привели выше:

    header("Expires: Thu, 31 Dec 2020 20:00:00 GMT");

    • Cache-Control :Cache-Control с заголовком легче работать, чем сExpires заголовком, потому что вам нужно только указать количество времени в секундах, чтоmax-age означает, что вам не нужно придумывать точный формат даты в строковой форме, которую легко ошибиться.. Кроме тогоCache-Control, позволяет несколько других опций, таких как возможность указать клиенту всегда повторно проверять кеш с помощью этойmustrevalidate опции иpublic когда вы хотите принудительно кешировать обычно не кешируемые запросы (т. е. запросы черезHTTPS ) и даже не кешировать, если это то, что вам нужно (т. е. вы можете заставить.GIF отслеживания рекламы размером 1×1 пиксель не кэшироваться.) Как будтоExpires я также не смог заставить это работать при тестировании ( любая помощь?) Следующий пример кэширует 24-часовой период (60 секунд на 60 минут на 24 часа):

    header("Cache-Control: max-age=".60*60*24.", public, must-revalidate");

    • Last-Modified / If-Modified-Since : тогда естьпара заголовкаLast-Modified ответа и заголовкаModified-Since Они также используют тот же формат даты по Гринвичу, что иExpires заголовок, но они выполняют рукопожатие между клиентом и сервером. PHP-скрипт должен отправитьLast-Modified заголовок (который, кстати, вы должны обновлять только тогда, когда ваш пользователь в последний раз обновляет свой пользовательский CSS), после чего браузер продолжит отправлять то же значение обратно в качествеIf-Modified-Since заголовка, и за это отвечает PHP-скрипт. сравнить сохраненное значение с отправленным браузером. Здесь PHP-скрипт должен принять решение между обслуживанием200 Ok файла304 Not Modified . Вот пример подачиLast-Modified заголовка с использованием текущего времени (которое нечто мы хотим сделать; см. более поздний пример того, что нам действительно нужно):

    header("Last-Modified: ". gmdate('D, d M Y H:i:s', time()).'GMT');

    А вот как вы читаете Last-Modified возвращаемое браузером через If-Modified-Since заголовок:

    $last_modified_to_compare = $_SERVER['HTTP_IF_MODIFIED_SINCE'];

    • ETag / If-None-Match : И, наконец, естьETag ответа и заголовкаIf-None-Match запроса. НаETag самом деле это просто токен, который наш PHP устанавливает для него уникальное значение (обычно основанное на текущей дате) и отправляет в браузер, а браузер возвращает его. Если текущее значение отличается от того, что возвращает браузер, ваш PHP-скрипт должен регенерировать контент, сервер в200 Ok противном случае ничего не генерирует и обслуживает304 Not Modified . Вот пример установки сETag использованием текущего времени:

    header("ETag: ". md5(gmdate('D, d M Y H:i:s', time()).'GMT'));

    А вот как вы читаете ETag возвращаемое браузером через If-None-Match заголовок:

    $etag_to_match = $_SERVER['HTTP_IF_NONE_MATCH'];

    Теперь, когда мы рассмотрели все это, давайте посмотрим на фактический код, который нам нужен:

    Обслуживание файла CSS через init иwp_enqueue_style()

    Вы этого не показали, но я решил показать это на благо других. Вот вызов функции, который сообщает WordPress использовать my_theme_css.php CSS. Это можно сохранить в functions.php файле темы или даже в плагине, если это необходимо:

    <?php
    add_action('init','add_php_powered_css');
    function add_php_powered_css() {
      if (!is_admin()) {
        $version = get_theme_mod('my_custom_css_version',"1.00");
        $ss_dir = get_stylesheet_directory_uri();
        wp_enqueue_style('php-powered-css', 
            "{$ss_dir}/my_theme_css.php",array(),$version);
      }
    }
    

    Следует отметить несколько моментов:

    • Используйте,is_admin() чтобы избежать загрузки CSS в админке (если вы этого не хотите…),
    • Использованиеget_theme_mod() для загрузки CSS с версией по умолчанию 1.00 (подробнее об этом чуть позже),
    • Использованиеget_stylesheet_directory_uri() для получения правильного каталога для текущей темы, даже если текущая тема является дочерней темой,
    • Использованиеwp_enqueue_style() для постановки CSS в очередь, чтобы позволить WordPress загрузить его в нужное время, где 'php-powered-css' произвольное имя для ссылки в качестве зависимости позже ( при необходимости ), а пустое значение array() означает, что этот CSS не имеет зависимостей ( хотя в реальном мире он часто имел бы один или несколько ), и
    • Использование$version ; Вероятно, самый важный из них — мы советуем wp_enqueue_style() добавить ?ver=1.00 параметр к /my_theme_css.php URL-адресу, чтобы при изменении версии браузер рассматривал его как совершенно другой URL-адрес (подробнее об этом чуть позже).

    Настройка $version и Last-Modified когда пользователь обновляет CSS

    Вот в чем хитрость. Каждый раз, когда пользователь обновляет свой CSS, вы хотите обслуживать контент, а не ждать, пока 2020 тайм-аут кеша каждого браузера не истечет, верно? Вот функция, которая в сочетании с моим другим кодом сделает это. Каждый раз, когда вы сохраняете CSS, обновленный пользователем, используйте эту функцию или функциональность, подобную той, что содержится внутри:

    <?php
    function set_my_custom_css($custom_css) {
      $new_version = round(get_theme_mod('my_custom_css_version','1.00',2))+0.01;
      set_theme_mod('my_custom_css_version',$new_version);
      set_theme_mod('my_custom_css_last_modified',gmdate('D, d M Y H:i:s',time()).' GMT');
      set_theme_mod('my_custom_css',$custom_css);
    }
    

    Функция set_my_custom_css() автоматически увеличивает текущую версию на 0,01 (это было просто произвольное значение приращения, которое я выбрал), а также устанавливает дату последнего изменения прямо сейчас и, наконец, сохраняет новый пользовательский CSS. Чтобы вызвать эту функцию, это может быть так же просто, как это (где new_custom_css, скорее всего, будет назначено через пользователя $_POST, а не путем жесткого кодирования, как вы видите здесь) :

    <?php
    $new_custom_css = 'body {background-color:orange;}';
    set_my_custom_css($new_custom_css);
    

    Что подводит нас к последнему, хотя и важному шагу:

    Создание CSS из PHP-скрипта

    Наконец мы видим мясо, сам my_theme_css.php файл. На высоком уровне он проверяет как If-Modifed-Since сохраненное Last-Modified значение, так и то If-None-Match, ETag которое было получено из сохраненного Last-Modified значения, и, если ни одно из них не изменилось, просто устанавливает заголовок 304 Not Modifed и ветви до конца.

    Однако, если какой-либо из них изменился, он генерирует файлы Expires, Cache-Control . Last-Modified и Etag заголовки, а также 200 Ok и указывает, что тип контента text/css . Нам, вероятно, все это не нужно, но, учитывая, насколько привередливым может быть кэширование с разными браузерами и прокси, я думаю, что не помешает охватить все основы. (И любой, у кого больше опыта с кэшированием HTTP и WordPress, пожалуйста, отзовитесь, если я ошибаюсь в каких-то нюансах.)

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

    <?php
    
      $s = $_SERVER;
    
      include_once("{$s['DOCUMENT_ROOT']}/wp-load.php");
    
      $max_age = 60*60*24; // 24 hours
      $now = gmdate('D, d M Y H:i:s', time()).'GMT';
      $last_modified = get_theme_mod('my_custom_css_last_modified',$now);
      $etag = md5($last_modified);
    
      if (strtotime($s['HTTP_IF_MODIFIED_SINCE']) >= strtotime($last_modified) || $s['HTTP_IF_NONE_MATCH']==$etag) {
        header('HTTP/1.1 304 Not Modified');
      } else {
        header('HTTP/1.1 200 Ok');
        header("Expires: " . gmdate('D, d M Y H:i:s', time()+$max_age.'GMT'));
        header("Cache-Control: max-age={$mag_age}, public, must-revalidate");
        header("Last-Modified: {$last_modified}");
        header("ETag: {$etag}");
        header('Content-type: text/css');
        echo_default_css();
        echo_custom_css();
      }
      exit;
    
    function echo_custom_css() {
      $custom_css = get_theme_mod('my_custom_css');
      if (!empty($custom_css))
        echo "\n{$custom_css}";
    }
    
    function echo_default_css() {
      $default_css =<<<CSS
    body {background-color:yellow;}
    CSS;
      echo $default_css;
    }
    

    Итак, с этими тремя основными битами кода; 1.) add_php_powered_css() функция, вызываемая init хуком, 2.) set_my_custom_css() функция, вызываемая любым кодом, позволяет пользователю обновлять свой собственный CSS, и, наконец, 3.) my_theme_css.php вы должны в значительной степени это лизать.

    Дальнейшее чтение

    Помимо тех, которые уже были связаны, я наткнулся на несколько других статей, которые, как мне показалось, были действительно полезными по этому вопросу, поэтому я решил, что должен связать их здесь:

    Эпилог:

    Но было бы упущением оставить тему без заключительного комментария.

    Истекает через 2020 ? Наверное, слишком экстремально.

    Во-первых, я действительно не думаю, что вы хотите установить Expires 2020 год. Любые браузеры или прокси-серверы, которые уважают Expires, не будут повторно запрашивать даже после того, как вы внесли много изменений CSS. Лучше установить что-то разумное, например, 24 часа (как я сделал в своем коде), но даже это расстроит пользователей в течение дня, в течение которого вы вносите изменения в жестко запрограммированный CSS, но забываете указать номер версии. Умеренность во всем?

    В любом случае, это может быть излишеством!

    As I was reading various articles to help me answer your question I came across the following from Mr. Cache Tutorial himself, Mark Nottingham:

    The best way to make a script cache-friendly (as well as perform better) is to dump its content to a plain file whenever it changes. The Web server can then treat it like any other Web page, generating and using validators, which makes your life easier. Remember to only write files that have changed, so the Last-Modified times are preserved.

    Несмотря на то, что весь этот код я написал здорово, и его было весело писать (да, я действительно это признал), может быть, лучше просто генерировать статический файл CSS каждый раз, когда пользователь обновляет свой собственный CSS, и позволить Apache делать всю тяжелую работу. как это было рождено делать? Я просто говорю…

    Надеюсь это поможет!

    • 0
  3. Попробуйте закодировать его так:

    <?php $my_custom_css = get_theme_mod('my_custom_css');
      if(!empty($my_custom_css)) {
        echo $my_custom_css;
      }
    ?>
    

    Это должно помочь вам обойти любые проблемы с областью действия get_theme_mod() функции.

    • 0

Оставить ответ

You must login to add an answer.