【问题标题】:WordPress filter to modify final html outputWordPress过滤器修改最终的html输出
【发布时间】:2009-04-21 13:10:22
【问题描述】:

WordPress 具有强大的过滤器支持,可以获取各种特定的内容位并在输出之前对其进行修改。就像the_content 过滤器一样,它可以让您在帖子输出到屏幕之前访问它的标记。

我正在尝试找到一个包罗万象的过滤器,它可以让我在输出之前完整地修改最终标记。

我已多次浏览过滤器列表,但没有任何反应: https://codex.wordpress.org/Plugin_API/Filter_Reference

有人知道吗?

【问题讨论】:

    标签: wordpress


    【解决方案1】:

    WordPress 没有“最终输出”过滤器,但您可以组合一个。下面的示例位于我为项目创建的"Must Use" 插件中。

    注意:我没有测试过任何可能使用“关闭”操作的插件。

    插件通过遍历所有打开的缓冲区级别、关闭它们并捕获它们的输出来工作。然后它触发“final_output”过滤器,回显过滤后的内容。

    遗憾的是,WordPress 执行几乎完全相同的过程(关闭打开的缓冲区),但实际上并没有捕获缓冲区进行过滤(只是刷新它),因此其他“关闭”操作将无法访问它。因此,以下操作的优先级高于 WordPress。

    wp-content/mu-plugins/buffer.php

    <?php
    
    /**
     * Output Buffering
     *
     * Buffers the entire WP process, capturing the final output for manipulation.
     */
    
    ob_start();
    
    add_action('shutdown', function() {
        $final = '';
    
        // We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
        // that buffer's output into the final output.
        $levels = ob_get_level();
    
        for ($i = 0; $i < $levels; $i++) {
            $final .= ob_get_clean();
        }
    
        // Apply any filters to the final output
        echo apply_filters('final_output', $final);
    }, 0);
    

    挂钩到 final_output 过滤器的示例:

    <?php
    
    add_filter('final_output', function($output) {
        return str_replace('foo', 'bar', $output);
    });
    

    编辑:

    此代码使用匿名函数,仅在 PHP 5.3 或更高版本中受支持。如果您正在使用 PHP 5.2 或更早版本运行网站,那么您就是在伤害自己。 PHP 5.2 于 2006 年发布,尽管 Wordpress(edit: in WP version )仍然支持它,但你不应该使用它。

    【讨论】:

    • 注意:我只在 3.8 版本中测试过。
    • 非常感谢,这是最优雅的解决方案。
    • 为什么是count(ob_get_level())?实际上 ob_get_level() 返回级别(int)。试试while(ob_get_level()) $final .= ob_get_clean();
    • 自发布以来,我已经在更多项目中使用了它,并且从 3.8 开始使用所有版本的 WP。我没有遇到任何问题。
    • 像魅力一样工作 - 4.9.8
    【解决方案2】:

    这个问题可能很老了,但我找到了更好的方法:

    function callback($buffer) {
      // modify buffer here, and then return the updated code
      return $buffer;
    }
    
    function buffer_start() { ob_start("callback"); }
    
    function buffer_end() { ob_end_flush(); }
    
    add_action('wp_head', 'buffer_start');
    add_action('wp_footer', 'buffer_end');
    

    说明 这个插件代码注册了两个动作——buffer_startbuffer_end

    buffer_start 在 html 标头部分的末尾执行。参数callback 函数在输出缓冲结束时调用。这发生在页面的页脚,当第二个注册操作 buffer_end 执行时。

    callback 函数用于添加代码以更改输出值($buffer 变量)。然后你只需返回修改后的代码,页面就会显示出来。

    备注 请务必为 buffer_startbuffer_endcallback 使用唯一的函数名称,以免它们与您可能在插件中拥有的其他函数发生冲突。

    【讨论】:

    • 您可以为示例添加前缀或后缀:buffer_start_so_772510so_772510_callback(我更喜欢添加后缀,因为这样更易于阅读)。这样,当代码出现在其他地方时,我们就知道它来自哪里;)
    • 当您要修改或删除的内容存在于页脚元素之后时,此方法不起作用
    • 我推荐使用 kwoodfriend 的解决方案,因为它更安全(例如,您可以确保是最后一个操作输出的人)。
    • 有没有办法在代码中包含headers,这样代码也可以替换headers?
    【解决方案3】:

    AFAIK,没有钩子,因为主题使用的 HTML 不会被 WordPress 处理。

    不过,您可以通过use output buffering 获取最终的 HTML:

    <?php
    // example from php.net
    function callback($buffer) {
      // replace all the apples with oranges
      return (str_replace("apples", "oranges", $buffer));
    }
    ob_start("callback");
    ?>
    <html><body>
    <p>It's like comparing apples to oranges.</p>
    </body></html>
    <?php ob_end_flush(); ?>
    /* output:
       <html><body>
       <p>It's like comparing oranges to oranges.</p>
       </body></html>
    */
    

    【讨论】:

    • 可以使用php register_shutdown_function 结束缓冲,取回html。
    • 这有一个缺点,你不能在回调中调用ob_start, ob_clean, ..,这是特定缓存逻辑所需要的。 php.net/manual/en/…
    【解决方案4】:

    @jacer,如果你使用下面的钩子,header.php 也会被包含进来。

    function callback($buffer) {      
        $buffer = str_replace('replacing','width',$buffer);
        return $buffer; 
    }
    
    function buffer_start() { ob_start("callback"); } 
    function buffer_end() { ob_end_flush(); }
    
    add_action('after_setup_theme', 'buffer_start');
    add_action('shutdown', 'buffer_end');
    

    【讨论】:

    • 尽量不要发表引用另一个答案的帖子(并且需要阅读另一个答案才能获得上下文);你的答案与你引用的答案越分离,就越难理解你在说什么。此外,发布基于其他答案的答案并不一定是坏事,只要您在应得的地方给予肯定。
    • 此解决方案效果不佳。 buffer_start 被调用两次,而 buffer_end 从不被调用。我用 debug_log 检查了它。最好坚持科斯的回答
    【解决方案5】:

    我使用这篇文章(kfriend)的最佳解决方案有一段时间了。它使用mu-plugin 来缓冲整个输出。

    但是这个解决方案破坏了wp-super-cache 的缓存,当我上传mu-plugin 时没有生成超级缓存文件。

    所以:如果你使用wp-super-cache,你可以像这样使用这个插件的过滤器:

    add_filter('wp_cache_ob_callback_filter', function($buffer) {
        $buffer = str_replace('foo', 'bar', $buffer);
        return $buffer;
    });
    

    【讨论】:

    • 我正在尝试像这样使用 wp 超级缓存过滤器,但它不起作用.. wp-rocket 也有类似的过滤器,称为rocket_buffer,这也不起作用。当我使用过滤器名称 Rocket_buffer 时,我的插件工作正常,wp-rocket 可以缩小 html 和 css 但缓存的 html 文件不会在 /cache 目录中生成(对于 wp 超级缓存也是如此。没有生成文件)。请问有什么建议吗?我非常感谢您对此的帮助。
    【解决方案6】:

    修改https://stackoverflow.com/users/419673/kfriend答案。

    所有代码都在functions.php上。你可以对“final_output”过滤器上的 html 做任何你想做的事情。

    在您主题的“functions.php”上

    //we use 'init' action to use ob_start()
    add_action( 'init', 'process_post' );
    
    function process_post() {
         ob_start();
    }
    
    
    add_action('shutdown', function() {
        $final = '';
    
        // We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
        // that buffer's output into the final output.
        $levels = ob_get_level();
    
        for ($i = 0; $i < $levels; $i++) {
            $final .= ob_get_clean();
        }
    
        // Apply any filters to the final output
        echo apply_filters('final_output', $final);
    }, 0);
    
    add_filter('final_output', function($output) {
        //this is where changes should be made
        return str_replace('foo', 'bar', $output); 
    });
    

    【讨论】:

    • 您介意为经验不足的人添加一句话吗?
    • 太棒了,该解决方案对我有用,非常感谢
    【解决方案7】:

    您可以尝试查看 wp-includes/formatting.php 文件。例如,wpautop 函数。 如果您正在寻找对整个页面进行操作,请查看 Super Cache 插件。这会将最终网页写入文件以进行缓存。看看这个插件是如何工作的可能会给你一些想法。

    【讨论】:

      【解决方案8】:

      确实,最近在 WP-Hackers 邮件列表上讨论了整页修改的主题,似乎一致认为使用 ob_start() 等进行输出缓冲是唯一真正的解决方案。也有一些关于它的优点和缺点的讨论:http://groups.google.com/group/wp-hackers/browse_thread/thread/e1a6f4b29169209a#

      总结:它可以工作并且在必要时是最佳解决方案(例如在 WP-Supercache 插件中),但会降低整体速度,因为您的内容不允许在准备好时发送到浏览器,而是必须等待完整文档被渲染(对于 ob_end() ),然后您才能处理它并将其发送到浏览器。

      【讨论】:

        【解决方案9】:

        为了简化之前的答案,只需在functions.php 中使用它:

        ob_start();
        add_action('shutdown', function () {
            $html = ob_get_clean();
            // ... modify $html here
            echo $html;
        }, 0);
        

        【讨论】:

          【解决方案10】:

          我在使用此代码时遇到了问题,因为我最终得到的似乎是页面的原始来源,因此某些插件对页面没有影响。我现在正在尝试解决这个问题 - 我没有找到太多关于从 WordPress 收集输出的最佳实践的信息。

          更新及解决方案:

          来自 KFRIEND 的代码对我不起作用,因为它从 WordPress 捕获未处理的源,实际上与最终在浏览器中的输出不同。我的解决方案使用全局变量来缓冲内容可能并不优雅——但至少我知道收集到的 HTML 与传递给浏览器的 HTML 相同。可能是插件的不同设置会产生问题,但感谢上面 Jacer Omri 的代码示例,我最终得到了这个。

          在我的情况下,此代码通常位于主题文件夹中的 functions.php 中。

          $GLOBALS['oldschool_buffer_variable'] = '';
          function sc_callback($data){
              $GLOBALS['final_html'] .= $data;
              return $data;
          }
          function sc_buffer_start(){
              ob_start('sc_callback');
          }
          function sc_buffer_end(){
              // Nothing makes a difference in my setup here, ob_get_flush() ob_end_clean() or whatever
              // function I try - nothing happens they all result in empty string. Strange since the
              // different functions supposedly have very different behaviours. Im guessing there are 
              // buffering all over the place from different plugins and such - which makes it so 
              // unpredictable. But that's why we can do it old school :D
              ob_end_flush();
          
              // Your final HTML is here, Yeeha!
              $output = $GLOBALS['oldschool_buffer_variable'];
          }
          add_action('wp_loaded', 'sc_buffer_start');
          add_action('shutdown', 'sc_buffer_end');
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-06-29
            • 2022-06-22
            • 2014-03-13
            • 1970-01-01
            • 1970-01-01
            • 2013-02-05
            • 1970-01-01
            相关资源
            最近更新 更多