WordPress过滤器修改最终的html输出

时间:2009-04-21 13:10:23

标签: wordpress

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

我正在尝试找到一个全能的过滤器,它让我在输出之前完成修改最终标记的最后一次破解。有人知道吗?

我已多次浏览过滤器列表,但没有任何内容突然出现在我面前: http://adambrown.info/p/wp_hooks/hook/filters

(我已经针对这个问题点了一些特定于WordPress的社区,但没有收到一个回复​​,我以为我会转向那个值得尊敬的SO。)

11 个答案:

答案 0 :(得分:50)

WordPress没有"最终输出"过滤器,但你可以一起破解。以下示例位于我为项目创建的"Must Use"插件中。

注意:我没有使用任何可能使用" shutdown"的插件进行测试。动作。

插件通过迭代所有打开的缓冲区级别,关闭它们并捕获它们的输出来工作。然后它会触发" final_output"过滤,回显过滤后的内容。

可悲的是,WordPress执行几乎完全相同的过程(关闭打开的缓冲区),但实际上并没有捕获缓冲区进行过滤(只是刷新它),所以额外的"关闭"动作无法访问它。因此,以下操作优先于WordPress。

可湿性粉剂内容/亩-插件/ 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(编辑:在WP版本&lt; 5.2 中)STILL支持它,也不应该使用它。

答案 1 :(得分:19)

这个问题可能很旧,但我找到了一个更好的方法。

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的唯一函数名称,这样它们就不会与插件中的其他函数冲突。

答案 2 :(得分:18)

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

然而,你可以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>
*/

答案 3 :(得分:13)

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

答案 4 :(得分:3)

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

答案 5 :(得分:3)

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

总结一下:它是有效的,并且是必要时的最佳解决方案(例如在WP-Supercache插件中),但会降低整体速度,因为您的内容不允许在准备好时发送到浏览器,而是必须等待完整文档呈现(对于ob_end()),然后由您处理并发送到浏览器。

答案 6 :(得分:2)

一段时间以来,我一直在使用此帖子的最佳解决方案(由kfriend进行)。它使用X = [[[X1, X2, X3],[X1, X4, X5, X6]], [[0],[X3, X4]]] Y = [[[Y1, Y2, Y3, Y4],[0]], [[Y4, Y5, Y6],[Y1]]] 缓冲整个输出。

但是此解决方案中断了mu-plugin的缓存,并且在我上载wp-super-cache时没有生成任何超级缓存文件。

因此:如果您使用的是mu-plugin,则可以使用此插件的过滤器,如下所示:

wp-super-cache

答案 7 :(得分:2)

修改后的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); 
});

答案 8 :(得分:1)

我遇到了这段代码的问题,因为我最终看起来似乎是页面的原始来源,所以一些插件对页面没有影响。我现在正试图解决这个问题 - 我没有找到有关从WordPress收集输出的最佳实践的更多信息。

更新和解决方案:

来自KFRIEND的代码对我没有用,因为它从WordPress捕获未处理的源,而不是实际上在浏览器中结束的相同输出。我的解决方案可能不是优雅使用全局变量来缓冲内容 - 但至少我知道获得与传递给浏览器相同的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');

答案 9 :(得分:1)

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

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

答案 10 :(得分:0)

在使用输出缓冲区之前,请先尝试使用JavaScript解决此问题。

假设您要在加载iframe时添加微调器,例如:

(function ($) {

    $(document).ready(function () {
        showSpinnerWhileIFrameLoads();
    });

    function showSpinnerWhileIFrameLoads() {
        var iframe = $('iframe');
        if (iframe.length) {
            $(iframe).before('<div id=\'spinner\'><i class=\'fa fa-spinner fa-spin fa-3x fa-fw\'></i></div>');
            $(iframe).on('load', function() {
                document.getElementById('spinner').style.display='none';
            });
        }
    }

})(jQuery);

使该想法适应您的需求,通常,您应该能够使用JavaScript处理HTML输出,而无需弄乱可能会破坏缓存的输出缓冲区。