生成动态javascript / CSS的解决方案


15

假设您需要根据当前上下文生成JavaScript或CSS代码。

例如,您在主页上有一个表单,该表单在提交时会触发ajax请求,而在单个页面上有另一种表单。或者对于CSS,您想要创建一个主题,允许其用户构建自己的布局,更改颜色等。

到目前为止,我看到的解决方案是:

  1. 将代码包含在文档的开头部分(如果是JS,则在结尾处)

  2. 进行特殊请求以输出代码,例如site.com?get_assets。这很慢,因为WP被加载了两次。

  3. 将其存储在临时文件中一定时间,然后从那里加载它。对于公共主题或插件不是很可靠。

  4. 仅Javascript-通过将其放入每次加载的普通文件中使其变为静态。在这种情况下,您将必须使代码处理任何情况

你认识别人吗 你会走哪条路?


解决方案1遇到的一个问题是浏览器缓存,重新加载页面后代码未刷新。
Aurovrata

Answers:


9

另一个选项,取决于您需要传递的参数类型。我们将其称为(2a)。您还可以创建PHP脚本,该脚本输出动态生成的text/csstext/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。

40K的CSS或40K的JS几乎总是可以拆分为<1K,这实际上取决于动态数据,其余的可以在静态外部文件中指定,然后使用级联(对于CSS)或全局可访问的方式重新组合变量(对于JS,是全局变量,DOM元素或您喜欢的其他任何笨拙的漏洞)。


辉煌的答案!
scribu

2
只是一小部分:对于JS,我们可以使用wp_localize_sciprt添加动态变量。
Anh Tran

6

动态CSS情况非常简单。

只需创建一个在<style type="text/css"></style>标签内部输出动态CSS定义的函数,然后将该函数挂接到即可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相同)。这就是我现在正在做的,但是如果您有40K的CSS,您会得到一个庞大的html文档
onetrickpony

1
但是那些40K的CSS必须输出到某个地方,对吧?并且,绝对与#1相同,但是是在WordPress中注入动态CSS 的正确方法。:)
Chip Bennett

2

我想了一段时间。您的问题让我重新开始。不知道这是一个好主意,所以我希望专家对此发表意见。

如果我在管理员保存数据时通过php编写javascript / css文件怎么办。直到用户再次更改布局(用户可能不会经常这样做)之前,这将是一次写入。这样,当用户保存数据时,我们仅访问数据库一次用户设置。

写入文件后,它将是一个常规的javascript / css文件,因此我们不必在每次加载主题时都调用数据库。

需要回答的一个问题:当访问者尝试用php编写文件时立即访问该网站时,会发生什么?

让我知道你的想法。


如果在这些文件中生成文件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,基本上有相同的作用。例如,您将使用它遍历所有定制程序mod,并将它们收集在名为的字符串中$all_mods,然后将其添加到主样式表中:

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

-2

创建一个动态JS.php文件,并将重要的query_vars馈入其中。中的这些变量$_GET将帮助文件确定上下文,并且可以在其中缓存并readfile()用于将来的请求...执行任何操作。

只要确保该文件先加载了文件wp-load.php,就可以访问WP函数。使用相对于当前文件夹的相对路径,(dirname(__FILE__))或者仅在文件夹结构中使用digg降序定位,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递减结构的复杂结构,父插件可以与可直接访问的文件共享信息。带有呈现CSS / JS的动态PHP文件的父插件可以将的文件写入文件realpath()wp-load.php而独立文件可以使用该文件。对于0.1%的WP用户而言,这将是一个问题。我认为那些移动文件夹并且不遵循正常结构的人知道他们在做什么,并且可能可以wp-load.php直接加载需要加载的PIMP插件。


可爱!讨厌者,请附上解释。开导我。谢谢;)xoxo
EarnestoDev 2011年

包含wp-load.php主题或插件文件是不明智的做法,因为wp-contentand / or plugins 目录可能位于根WP目录的相对位置。记住WP_CONTENT_DIR和WP_PLUGINS_DIR。
scribu

1
@scribu并且独立文件可以与父插件协作。父插件可以将wp-load.php存储在它所在的文件夹中,动态js生成器可以从那里读取它。简单...
EarnestoDev 2011年

1
是的,父插件方法可以工作。在您的答案中写下来,我将删除我的不赞成投票。PS:这个网站是英文的;如果您继续用罗马尼亚语发言,您可能会遇到问题。
scribu

5
降低态度。手动堆芯加载是可行的技术,但对于大多数事情而言,并不是一个好的首选。没有人怀疑您可以使它起作用。投票是关于您答案的质量,而不是您的大脑。
罗斯特(Rarst)2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.