Шорткод всегда отображается в верхней части страницы
Я использую шорткод для подключения различных циклов через файлы loops-name.php. По какой-то причине он всегда отображается в верхней части страницы. Я погуглил и выяснил, что использование echo вместо return вызывает эту проблему, но в моем коде я не использую echo. Вот мой шорткод:
// настройка шорткода для использования
function friendly_loop_shortcode( $atts, $content = null ) {
extract( shortcode_atts( array(
'category' => '',
'module' => ''
), $atts ) );
include(locate_template('loop-'.$module.'.php'));
}
Есть идеи, почему это происходит?

Вы можете буферизировать вывод следующим образом:
ob_start();
include(locate_template('loop-'.$module.'.php'));
return ob_get_clean();
РЕДАКТИРОВАТЬ. Я попробовал это, работает нормально.
function friendly_loop_shortcode( $atts, $content = null ) {
extract( shortcode_atts( array(
'category' => '',
'module' => ''
), $atts ) );
ob_start();
include(locate_template('loop-'.$module.'.php'));
$output = ob_get_clean();
//print $output; // debug
return $output;
}
if (!is_admin()) {
add_shortcode('test', 'friendly_loop_shortcode' );
}

Не используйте буферизацию вывода, если есть другие способы.

Ваш подключаемый файл, по сути, выводит HTML через echo. Например:
<?php
//Некоторый PHP-код
echo 'test';
//Еще немного PHP
?>
То же самое, что и:
<?php
//Некоторый PHP-код
?>
test
<?php
//Еще немного PHP
?>
В обоих случаях текст выводится сразу же, а не возвращается. Поскольку он выводится, он появляется перед основным контентом страницы. Вам нужно именно возвращать значение, чтобы оно было включено в контент.
Как отметил @RutwickGangurde - необычно подключать файл шаблона в шорткоде.

Спасибо, я этого не знал. Значит, мне нужно поместить весь код в переменную и вернуть его? Что касается включения файла шаблона - я хочу сделать максимально простым для пользователей темы возможность кастомизации, а огромный файл шорткода, вложенный где-то в глубине директории темы, не совсем идеален для них.

"я хочу сделать максимально простым для пользователей темы возможность кастомизации" - Сколько же слоев абстракции действительно необходимо? У вас есть пользовательский файл шаблона внутри шорткода. Я не вижу, как это упрощает жизнь пользователям. Если вы хотите дать возможность добавлять статический контент ко всем записям, просто определите dynamic_sidebar()
внутри цикла и позвольте пользователям добавлять виджеты.

Большинство пользователей темы не оценят необходимости продираться через огромный файл шорткодов, чтобы изменить простой CSS-класс на фронтенде. Если я разобью всё с использованием стандартной системы loop-name.php, то им будет гораздо быстрее найти то, что нужно. Не идеально, но я должен держать их довольными ;)

Это правильный ответ, потому что причиной проблемы было косвенное "echo" HTML, вместо того чтобы собрать HTML в переменную и "вернуть" её в конце функции. В документации WordPress можно найти предупреждение: *** Помните, что нужно использовать return, а не echo - всё, что выводится через echo, отобразится в браузере, но не в правильном месте на странице.***
