Tạo tập tin CSS một cách linh hoạt bằng cách sử dụng tập lệnh PHP?


7

Là một phần trong nỗ lực tăng tốc các chủ đề cho khách hàng của tôi, tôi đang phân phối CSS của mình thông qua tệp PHP động. Vào cuối cuộc gọi chẳng hạn my_theme_css.php:

Điều này cho phép tôi thêm các tiêu đề Hết hạn vào CSS và JavaScript của mình như vậy:

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

Sau đó tôi muốn cho phép người dùng thêm CSS tùy chỉnh của riêng mình vì vậy tôi đã thiết lập các mục sau:

<?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; 
}
?> 

Tôi đã thêm các tùy chọn chủ đề áp dụng. Nhưng những gì tôi đang tìm kiếm là get_theme_mod()nó không hoạt động do vấn đề phạm vi (tôi tưởng tượng.) Có gợi ý nào về cách khắc phục điều này không?

Tôi có thể thêm đoạn mã sau:

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

Trong <style></style>các thẻ trong tiêu đề và điều đó sẽ hoạt động tốt, mong rằng tôi không muốn nội tuyến CSS, tôi muốn nó trên tệp CSS chính với tiêu đề hết hạn.


Không phải một tập tin css tĩnh sẽ tốt hơn cho hiệu suất? Ngoài ra còn có một số lời khuyên tốt mà tôi nhận được về một câu hỏi tương tự tôi đã hỏi.
Chris_O

@Chris_O Nếu đây là một vài quy tắc kiểu tôi sẽ nói có nhưng với việc sử dụng nặng hơn thì nội tuyến có nghĩa là 100 dòng bổ sung được tải xuống mỗi khi một trang được tải so với một biểu định kiểu bên ngoài có thời hạn sử dụng trong tương lai xa có thể được lưu trong bộ nhớ cache
Ashley G

@Ash G: Cung cấp tệp CSS tĩnh và thiết lập bộ đệm ẩn trong Máy chủ web đúng cách. Đó là đề nghị của tôi.
hakre

@hakre Điều này sẽ được sử dụng trong trường hợp truy cập ở cấp độ đó trên máy chủ không khả dụng hoặc khi người dùng cuối không đủ kiến ​​thức để thực hiện những thay đổi đó. Vì lý do này, mã cần phải ở cấp chủ đề.
Ashley G

@Ash G: Nếu đó là trường hợp, thì đó là dựa vào PHP, đúng vậy.
hakre

Câu trả lời:


15

Xin chào @Ash G:

Tôi đã không theo dõi 100% khi bạn đặc biệt gặp vấn đề vì vậy tôi không chắc chắn tôi thực sự có thể trả lời từng vấn đề của bạn nhưng tôi có thể giải thích cách thực hiện việc này từ đầu . Và trừ khi những gì bạn đang làm có liên quan nhiều hơn một chút thì bạn đã đề cập đến nó một chút công việc hơn tôi nghĩ bạn đã dự đoán nhưng nó vẫn hoàn toàn có thể làm được. Và ngay cả khi tôi bao quát nhiều nền tảng mà bạn đã biết thì rất có thể những người khác có ít kiến ​​thức hoặc kinh nghiệm sẽ tìm thấy điều này thông qua Google và cũng được nó giúp đỡ.

Bootstrap WordPress với /wp-load.php

Điều đầu tiên chúng ta cần làm trong my_theme_css.phptệp của bạn là bootstrap các chức năng thư viện cốt lõi của WordPress. Các dòng tải mã sau đây /wp-load.php. Nó sử dụng $_SERVER['DOCUMENT_ROOT']để xác định vị trí gốc của trang web để bạn không phải lo lắng về nơi bạn lưu trữ tệp này trên máy chủ của mình; giả sử DOCUMENT_ROOTđược đặt chính xác vì nó luôn phải dành cho WordPress thì điều này sẽ khởi động WordPress:

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

Vì vậy, đó là phần dễ dàng. Tiếp đến là phần khó khăn ...

Các tập lệnh PHP phải xử lý tất cả các bộ đệm logic

Đây là nơi tôi cá là bạn có thể đã vấp ngã vì tôi chắc chắn đã làm như vậy khi tôi đang cố gắng tìm ra cách trả lời câu hỏi của bạn. Chúng ta đã quá quen với các chi tiết lưu trữ được xử lý bởi máy chủ web Apache đến nỗi chúng ta quên hoặc thậm chí không nhận ra rằng chúng ta phải tự làm mọi việc nặng nhọc khi tải CSS hoặc JS bằng PHP.

Chắc chắn tiêu đề hết hạn có thể là tất cả những gì chúng ta cần khi chúng ta có proxy ở giữa nhưng nếu yêu cầu gửi đến máy chủ web và tập lệnh PHP chỉ cần trả về nội dung và mã trạng thái "Ok" về bản chất bạn sẽ không có bộ nhớ đệm.

Trả lại "200 Ok" hoặc "304 không được sửa đổi"

Cụ thể hơn, tệp PHP của chúng tôi trả về CSS cần phản hồi chính xác với các tiêu đề yêu cầu được gửi bởi trình duyệt. Tập lệnh PHP của chúng tôi cần trả về mã trạng thái phù hợp dựa trên những gì các tiêu đề đó chứa. Nếu nội dung cần được phục vụ vì đó là yêu cầu lần đầu tiên hoặc vì nội dung đã hết hạn, tập lệnh PHP sẽ tạo ra tất cả nội dung CSS và trả về với "200 Ok" .

Mặt khác, nếu chúng tôi xác định dựa trên các tiêu đề yêu cầu liên quan đến bộ đệm mà trình duyệt máy khách đã có CSS ​​mới nhất, chúng tôi không nên trả lại bất kỳ CSS nào và thay vào đó trả về với "304 Không được sửa đổi" . Quá nhiều dòng mã cho điều này tương ứng (tất nhiên bạn sẽ không bao giờ sử dụng cả hai dòng này đến dòng khác, tôi chỉ hiển thị theo cách đó ở đây để thuận tiện) :

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

Bốn hương vị của bộ nhớ đệm HTTP

Tiếp theo chúng ta cần xem xét các cách khác nhau HTTP có thể xử lý bộ đệm. Đầu tiên là những gì bạn đề cập; Expires:

  • Hết hạn :ExpiresTiêu đềnàymong đợi một ngày ởđịnh dạng( chức năng PHPgmdate() )'D, d M Y H:i:s'' GMT'gắn thêm ( GMT là viết tắt của Giờ chuẩn Greenwich .) Về mặt lý thuyết nếu tiêu đề này được phục vụ trình duyệt và proxy xuôi dòng sẽ lưu trữ cho đến khi thời gian được chỉ định sau đó sẽ bắt đầu yêu cầu trang một lần nữa. Đây có lẽ là tiêu đề bộ nhớ đệm được biết đến nhiều nhất nhưng rõ ràng không phải là tiêu đề ưa thích để sử dụng; Kiểm soát bộ nhớ cache là tốt hơn . Điều thú vị trong thử nghiệm của tôilocalhostvới Safari 5.0 trên Mac OS XI là không bao giờ có thể khiến trình duyệt tôn trọngExpirestiêu đề; nó luôn luônđã yêu cầu tệp lại (nếu ai đó có thể giải thích điều này tôi rất biết ơn.) Đây là ví dụ bạn đã đưa ra ở trên:

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

  • Kiểm soát bộ đệm :Cache-ControlTiêu đề dễ làm việc hơn so vớiExpirestiêu đề vì bạn chỉ cần chỉ định số lượng thời gian tính bằng giây vìmax-agecó nghĩa là bạn không phải đưa ra định dạng ngày chính xác ở dạng chuỗi dễ bị sai . Ngoài ra,Cache-Controlcho phép một số tùy chọn khác như có thể yêu cầu khách luôn xác thực lại bộ đệm bằng cách sử dụngmustrevalidatetùy chọn vàpublickhi bạn muốn buộc lưu vào bộ đệm cho các yêu cầu không lưu trong bộ nhớ cache thông thường (tức là yêu cầu quaHTTPS) và thậm chí không lưu bộ đệm nếu đó là những gì bạn cần (tức là bạn có thể muốn buộc theo dõi quảng cáo 1x1 pixel .GIF không được lưu trong bộ nhớ cache.) Giống nhưExpirestôi cũng không thể để điều này hoạt động trong thử nghiệm ( có trợ giúp nào không?) Ví dụ sau lưu trữ trong khoảng thời gian 24 giờ (60 giây x 60 phút trong 24 giờ):

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

  • Last-Modified / If-Modified-Because : Sau đó, có cặpLast-Modifiedtiêu đề phản hồi vàModified-Sincecặp tiêu đềIf-request. Chúng cũng sử dụng định dạng ngày GMT giống nhưExpirestiêu đề sử dụng nhưng chúng bắt tay giữa máy khách và máy chủ. Tập lệnh PHP cần gửi mộtLast-Modifiedtiêu đề (nhân tiện, bạn chỉ nên cập nhật khi người dùng của bạn cập nhật CSS tùy chỉnh lần cuối) sau đó trình duyệt sẽ tiếp tục gửi lại giá trị tương tự như mộtIf-Modified-Sincetiêu đề và đó là trách nhiệm của tập lệnh PHP so sánh giá trị đã lưu với giá trị được gửi bởi trình duyệt. Đây là nơi tập lệnh PHP cần đưa ra quyết định giữa việc phục vụ a200 Okhoặc a304 Not Modified. Đây là một ví dụ về việc phục vụLast-Modifiedtiêu đề bằng cách sử dụng thời gian hiện tại ( không phảinhững gì chúng ta muốn làm; xem ví dụ sau để biết những gì chúng ta thực sự cần):

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

Và đây là cách bạn đọc Last-Modifiedtrình duyệt được trả về qua If-Modified-Sincetiêu đề:

$last_modified_to_compare = $_SERVER['HTTP_IF_MODIFIED_SINCE'];

  • ETag / If-none-Match : Và cuối cùng, cóETagtiêu đề phản hồi vàIf-None-Matchcặp tiêu đề yêu cầu. MãETagthực sự chỉ là một mã thông báo mà PHP của chúng tôi đặt nó thành một giá trị duy nhất (thường dựa trên ngày hiện tại) và gửi đến trình duyệt và trình duyệt trả về nó. Giá trị hiện tại khác với giá trị mà trình duyệt trả về tập lệnh PHP của bạn sẽ tạo lại nội dung mà máy chủ200 Oktạo ra không có gì và phục vụ a304 Not Modified. Dưới đây là ví dụ về cài đặtETagsử dụng thời gian hiện tại:

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

Và đây là cách bạn đọc ETagtrình duyệt được trả về qua If-None-Matchtiêu đề:

$etag_to_match = $_SERVER['HTTP_IF_NONE_MATCH'];

Bây giờ chúng tôi đã trình bày tất cả những gì chúng ta hãy xem mã thực tế chúng ta cần:

Phục vụ tệp CSS qua initwp_enqueue_style()

Bạn đã không thể hiện điều này nhưng tôi đoán rằng tôi sẽ thể hiện nó vì lợi ích của người khác. Đây là lời gọi hàm cho WordPress sử dụng my_theme_css.phpCSS của nó. Điều này có thể được lưu trữ trong functions.phptệp của chủ đề hoặc thậm chí trong một plugin nếu muốn:

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

Có một số điểm cần lưu ý:

  • Sử dụngis_admin() để tránh tải CSS khi ở trong quản trị viên (trừ khi bạn muốn điều đó ...),
  • Sử dụngget_theme_mod() để tải CSS với phiên bản mặc định 1.00(nhiều hơn một chút),
  • Sử dụngget_stylesheet_directory_uri() để lấy đúng thư mục cho chủ đề hiện tại, ngay cả khi chủ đề hiện tại là chủ đề con,
  • Sử dụngwp_enqueue_style() để xếp hàng CSS để cho phép WordPress tải nó vào thời điểm thích hợp trong đó 'php-powered-css'một tên tùy ý để tham chiếu như một phụ thuộc sau này ( nếu cần ) và trống array()có nghĩa là CSS này không có phụ thuộc ( mặc dù trong thế giới thực, nó thường có một hoặc nhiều ) và
  • Sử dụng$version ; Có lẽ là điều quan trọng nhất, chúng tôi đang yêu wp_enqueue_style()cầu thêm một ?ver=1.00tham số vào /my_theme_css.phpURL để nếu phiên bản thay đổi, trình duyệt sẽ xem nó như một URL hoàn toàn khác (Nhiều hơn một chút về điều đó).

Cài đặt $versionLast-Modifiedkhi người dùng cập nhật CSS

Vì vậy, đây là mẹo. Mỗi khi người dùng cập nhật CSS của họ, bạn muốn phân phát nội dung và không đợi cho đến khi 2020bộ nhớ cache của trình duyệt hết thời gian chờ, phải không? Đây là một chức năng kết hợp với mã khác của tôi sẽ thực hiện điều đó. Mỗi khi bạn lưu trữ CSS được người dùng cập nhật, hãy sử dụng chức năng hoặc chức năng này tương tự như những gì có trong:

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

Các set_my_custom_css()chức năng tự động increments phiên bản hiện tại của 0.01 (mà chỉ là một giá trị thặng dư tùy ý tôi nhặt) và nó cũng đặt ra ngày sửa đổi cuối cùng để ngay bây giờ và cuối cùng là lưu trữ CSS tùy chỉnh mới. Để gọi hàm này, nó có thể đơn giản như thế này (nơi new_custom_csscó thể sẽ được chỉ định thông qua người dùng được gửi $_POSTthay vì mã hóa như bạn thấy ở đây) :

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

Điều này đưa chúng ta đến bước cuối cùng mặc dù có ý nghĩa:

Tạo CSS từ PHP Script

Cuối cùng chúng ta cũng được xem thịt, my_theme_css.phpfile thực tế . Ở mức độ cao, nó kiểm tra cả If-Modifed-Since so với lưu Last-Modifiedgiá trị và If-None-Matchchống lại ETagđược bắt nguồn từ lưu Last-Modifiedgiá trị và nếu không có thay đổi chỉ đặt tiêu đề để 304 Not Modifedngành đến cùng.

Tuy nhiên, nếu một trong hai đã thay đổi, nó tạo ra Expires, Cache-Control. Last-ModifiedEtagcác tiêu đề cũng như a 200 Okvà chỉ ra rằng loại nội dung là text/css. Chúng tôi có lẽ không cần tất cả những thứ đó nhưng được đưa ra cách bộ nhớ đệm tinh vi có thể với các trình duyệt và proxy khác nhau mà tôi cho rằng nó không gây hại cho tất cả các cơ sở. (Và bất cứ ai có nhiều kinh nghiệm hơn với bộ nhớ đệm HTTP và WordPress, vui lòng bấm nút nếu tôi có bất kỳ sắc thái nào sai.)

Có một vài chi tiết trong đoạn mã sau nhưng tôi nghĩ bạn có thể tự mình giải quyết chúng:

<?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;
}

Vì vậy, với ba bit chính của mã; 1.) add_php_powered_css()chức năng được gọi bởi inithook, 2.) set_my_custom_css()chức năng được gọi bởi bất kỳ mã nào cho phép người dùng cập nhật CSS tùy chỉnh của họ và cuối cùng là 3.) my_theme_css.phpbạn nên thực hiện việc này.

Đọc thêm

Ngoài những bài đã được liên kết, tôi đã xem qua một vài bài viết khác mà tôi nghĩ là thực sự hữu ích về chủ đề này vì vậy tôi nghĩ rằng tôi nên liên kết chúng ở đây:

Phần kết:

Nhưng tôi sẽ hối hận khi rời khỏi chủ đề mà không đưa ra bình luận đóng.

Hết hạn trong 2020? Có lẽ là quá cực đoan.

Đầu tiên, tôi thực sự không nghĩ rằng bạn muốn thiết lập Expiresđến năm 2020. Bất kỳ trình duyệt hoặc proxy nào tôn trọng Expiressẽ không yêu cầu lại ngay cả khi bạn đã thực hiện nhiều thay đổi CSS. Tốt hơn là đặt một cái gì đó hợp lý như 24 giờ (như tôi đã làm trong mã của mình) nhưng ngay cả điều đó sẽ khiến người dùng thất vọng trong ngày mà bạn thực hiện các thay đổi trong CSS được mã hóa cứng mà quên nhưng số phiên bản được cung cấp. Điều độ trong tất cả mọi thứ?

Điều này có thể là tất cả quá mức cần thiết!

Khi tôi đang đọc các bài viết khác nhau để giúp tôi trả lời câu hỏi của bạn, tôi đã tìm thấy những điều sau đây từ chính Hướng dẫn của ông Cache , Mark Nottingham :

Cách tốt nhất để làm cho tập lệnh thân thiện với bộ đệm (cũng như hoạt động tốt hơn) là kết xuất nội dung của nó vào một tệp đơn giản bất cứ khi nào nó thay đổi. Sau đó, máy chủ Web có thể coi nó như bất kỳ trang Web nào khác, tạo và sử dụng trình xác nhận, điều này giúp cuộc sống của bạn dễ dàng hơn. Hãy nhớ chỉ ghi các tệp đã thay đổi, vì vậy thời gian sửa đổi lần cuối được giữ nguyên.

Mặc dù tất cả các mã này tôi đã viết nó rất hay và rất vui khi viết (vâng, tôi thực sự đã thừa nhận điều đó), có lẽ tốt hơn là chỉ tạo một tệp CSS tĩnh mỗi khi người dùng cập nhật CSS tùy chỉnh của họ và để Apache thực hiện mọi công việc nặng nhọc Giống như nó được sinh ra để làm gì? Tôi chỉ đang nói...

Hi vọng điêu nay co ich!


Xin chào Mike, Cảm ơn vì điều này. Bạn luôn đưa ra câu trả lời tuyệt vời như vậy! Tôi đã cố gắng tránh toàn bộ điều wp_load mặc dù ( ottopress.com/2010/dont-include-wp-load-please )
Ashley G

@Ash G: heh. Vâng, đó là lý do tại sao bạn không làm việc! ;-) get_theme_mod()là một phần của API WordPress vì vậy mà /wp-load.phpbạn không nhận được nó! Và API không phải là mô-đun, đó là tất cả hoặc không có gì. Nhưng tôi sẽ tranh luận trong khi nói chung, Otto không phải là vấn đề lớn nếu bạn lưu vào bộ nhớ cache trong 24 giờ hoặc lâu hơn với Expireshoặc Cache-Control. Và nếu bạn thực sự muốn tối ưu hóa, bạn có thể loại bỏ /wp-load.phpvà sử dụng các cuộc gọi MySQL thô để thay thế get_theme_mod()chức năng nếu bạn muốn; đó là mã tầm thường, chỉ có nhược điểm là phá vỡ các gói chi tiết lưu trữ mod chủ đề của API.
MikeSchinkel

@Ash G: Tất nhiên luôn có phần cuối cùng trong câu trả lời của tôi mà tôi đã bắt đầu với "Điều này có thể là tất cả quá mức cần thiết!" ... :-)
MikeSchinkel

@AshG : Ồ, và cảm ơn vì lời khen. Tôi học tốt nhất bằng cách dạy người khác và tôi đang cố gắng trở thành chuyên gia về mọi thứ cần biết về mã hóa cho WordPress, vì vậy đó là lý do tại sao tôi nỗ lực vào câu trả lời. Giúp đỡ người khác giúp tôi; đó là một chiến thắng cùng thắng , phải không? :-)
MikeSchinkel

1
Hi @Ash G : Vâng, bạn có thể sử dụng file_get_contents()và quét qua /wp-config.phptìm kiếm $table_prefixDB_HOST, DB_NAME, DB_USER, và DB_PASSWORD; đó sẽ không phải là mã khó để viết hay mã với quá nhiều chi phí (so với tất cả /wp-load.php) Điểm đáng suy ngẫm. :) Và cảm ơn cho sự lựa chọn và bỏ phiếu.
MikeSchinkel

0

Hãy thử mã hóa nó như sau:

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

Điều đó sẽ giúp bạn xung quanh bất kỳ vấn đề phạm vi với get_theme_mod()chức năng.


Cảm ơn đã giúp đỡ. Điều này không làm việc mặc dù. Tôi không hiểu tại sao điều này sẽ xoay quanh vấn đề phạm vi?
Ashley G

Tôi không hiểu tại sao sẽ có một vấn đề phạm vi với một chức năng ở nơi đầu tiên. Nhưng tôi nghĩ tôi đã chứng minh cách tôi thấy các tác vụ tương tự được thực hiện trong các plugin khác.
dgw
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.