Правильное использование буфера вывода
Я пытаюсь использовать действия для переопределения вызовов функций, которые у меня есть в шаблоне (чтобы упростить обновление определенных повторяющихся секций). Например, в archives.php
у меня следующее:
<?php get_header(); ?>
<?php roots_content_before(); ?>
<?php $page_for_posts = get_option( 'page_for_posts' ); if ($page_for_posts) { echo '<h1>' . get_the_title($page_for_posts) . '</h1>'; } ?>
<h3>
<?php
$term = get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
if ($term) {
echo $term->name;
} elseif (is_day()) {
printf(__('Ежедневные архивы: %s', 'roots'), get_the_date());
} elseif (is_month()) {
printf(__('Ежемесячные архивы: %s', 'roots'), get_the_date('F Y'));
} elseif (is_year()) {
printf(__('Годовые архивы: %s', 'roots'), get_the_date('Y'));
} elseif (is_author()) {
global $post;
$author_id = $post->post_author;
printf(__('Архивы автора: %s', 'roots'), get_the_author_meta('user_nicename', $author_id));
} else {
single_cat_title();
}
?>
</h3>
<?php echo category_description(); ?>
<?php roots_loop_before(); ?>
<?php get_template_part('loop', 'category'); ?>
<?php roots_loop_after(); ?>
<?php roots_content_after(); ?>
<?php get_footer(); ?>
Вы можете видеть некоторые функции, например roots_content_before();
В отдельном файле у меня следующее:
function roots_content_before() { do_action('roots_content_before'); }
и использую это следующим образом:
<?php
add_action('roots_content_before', 'roots_bootstrap_content_before');
function roots_bootstrap_content_before() { ?>
это некоторый текст
<?php }
?>
Из того, что я прочитал, особенно если я собираюсь иметь большие куски кода, я должен использовать буфер вывода, но когда я пытаюсь это сделать, я не получаю ничего:
<?php
add_action('roots_content_before', 'roots_bootstrap_content_before');
function roots_bootstrap_content_before() { ob_start(); ?>
это некоторый текст
<?php return ob_get_clean();
}
?>
Я думаю об этом совершенно неправильно? Я все еще учусь, но пытаюсь некоторое время без какого-либо успеха. Любые указания в правильном направлении были бы действительно оценены. Спасибо!

Нет, в данном случае буферизация вывода не нужна. Общее правило: не используйте буферизацию вывода, если в этом нет реальной необходимости.
Представьте, что произойдет, если кто-то другой из плагина также использует буферизацию вывода, и она пересекается с вашей:
// плагин
ob_start();
// позже, вы в своей теме
ob_start();
// вы вызываете функцию, в которую автор плагина добавил хук:
print ob_get_clean();
// вы вызываете *свою*:
return ob_get_clean();
// результат пустой!
Такие ситуации очень сложно отлаживать. Избегайте их.
Вам не нужна отдельная функция для простого вызова do_action()
. Просто напишите do_action('roots_content_before');
в своей теме.

Согласен с toscho здесь. Не используйте буферизацию вывода. Используйте действия и фильтры там, где это необходимо.

Привет, @toscho, я действительно ценю твой совет. Я только начал читать о буферизации вывода, но из той статьи сложилось впечатление, что это даёт прирост производительности. Есть он на самом деле или нет, но звучит так, будто если ты полностью контролируешь приложение, то это может быть полезно, но поскольку WordPress имеет тысячи плагинов, ты просто можешь напроситься на неприятности ;) Ещё раз спасибо!

@Zach Эта статья ошибочна с первой же строки. :) Отправляйте вывод пользователю как можно раньше. В темах с долгим выполнением кода я даже вызываю flush()
до и после медленного кода, чтобы ускорить отрисовку.

Прогрессивный рендеринг через множественные сбросы - стоит прочитать.

toscho, можно использовать вложенные буферы вывода. Хотя терять над ними контроль — не лучшая идея :)

@offroff В WordPress кто-то другой может добавить нежелательную вложенность. Поэтому не используйте это в плагинах или темах.

Этот ответ немного вводит в заблуждение. Он игнорирует ситуации, в которых можно без проблем использовать буферизацию вывода. Например, у вас есть функция, которая выводит некоторый HTML, и вы хотите вернуть этот HTML. Пока вы не запускаете общие действия или не вызываете функции WP, такие как get_header(), вы должны использовать буферизацию вывода для создания более читаемого кода.

@OneTrickPony В зависимости от точных операций, которые вы выполняете, можно раньше достичь лимита памяти при использовании буферизации вывода, потому что... ну... всё хранится в памяти до вызова ob_end_clean()
. Если вам действительно это нужно — используйте. Это то, что я сказал в своем ответе. :)

Ответ @toscho совершенно неверен.
Буферизация вывода может быть вложенной, не нужно беспокоиться о других плагинах.
В этой записи от 2009 года представлен очень элегантный способ получения и манипулирования конечным выводом WordPress.

Это звучит немного резко. Я думаю, что @toscho хотел сказать не то, что вложенность невозможна, а то, что если по какой-то причине вы вызовете ob_get_clean()
до того, как код, например, другого плагина, который запустил первый ob_start()
, вызовет ob_get_clean()
, то вы получите неожиданные результаты. Он просто предупреждает, что стоит использовать этот метод только в случае, если нет другого выхода, так как есть подводные камни, которые можно не заметить с первого взгляда.

Вы посмотрели вторую ссылку? Там есть отличное решение, которое как раз решает проблему этого вопроса. Нет ничего неожиданного во вложенности; попробуйте сами: ob_start();
echo "0";
ob_start();
echo "a";
echo ob_get_clean();
echo "1";
$a = ob_get_clean();
echo $a;

Честно говоря - нет, не посмотрел. Ещё раз повторю, что есть множество способов всё испортить, поэтому лучше использовать этот метод только когда нет другого выхода. На заметку: именно поэтому ответы только со ссылками не приветствуются здесь. Если бы вы добавили суть ваших ссылок в ответ, это сильно помогло бы.
