Подключение PHP файла в контенте с помощью [shortcode]
Вот что у меня есть
Я не могу найти способ, как просто подключить файл в редакторе контента с помощью шорткода.
Например, если я хочу подключить form.php внутри моей Контактной страницы, как это можно сделать используя шорткод?
Ниже код, с которым я пытался работать, но безуспешно.
Буду благодарен за любую помощь!
// Реализация шорткода
function magic_stuff($atts) {
// включаем буферизацию вывода для захвата результата выполнения скрипта
ob_start();
// подключаем файл (содержимое будет сохранено в буфере вывода)
include(TEMPLATEPATH.'/wp-content/themes/grainandmortar/inc_static/test.php');
// сохраняем и возвращаем контент, который был выведен
$content = ob_get_clean();
return $content;
}
//регистрируем обработчик шорткода
add_shortcode('magic', 'magic_stuff');
Вот ещё один способ сделать это, используя функцию WordPress get_template_part
:
function include_file($atts) {
$a = shortcode_atts( array(
'slug' => 'NULL',
), $atts );
if($a['slug'] != 'NULL'){
ob_start();
get_template_part($a['slug']);
return ob_get_clean();
}
}
add_shortcode('include', 'include_file');
Примеры использования:
[include slug="form"]
[include slug="sub-folder/filename_without_extension"]

Я модифицировал некоторый код из старой записи в блоге, чтобы реализовать это, а также добавил возможность прикреплять query-строки к файлу.
Оригинальный код принадлежит amberpanther.com, и, как оказалось, они также сделали из этого плагин.
//создаем шорткод [include], который принимает путь к файлу и query-строку
//эта функция была модифицирована из статьи на www.amberpanther.com, которую можно найти по ссылке ниже:
//http://www.amberpanther.com/knowledge-base/using-the-wordpress-shortcode-api-to-include-an-external-file-in-the-post-content/
//НАЧАЛО кода от amberpanther.com
function include_file($atts) {
//если указан путь к файлу
extract(
shortcode_atts(
array(
'filepath' => 'NULL'
), $atts
)
);
//НАЧАЛО модифицированной части кода для поддержки query-строк
//проверяем наличие query-строки переменных после пути к файлу
if(strpos($filepath,"?")) {
$query_string_pos = strpos($filepath,"?");
//создаем глобальную переменную для query-строки, чтобы мы могли получить к ней доступ в подключаемых файлах, если нужно
//также выделяем ее из чистого имени файла, которое сохраним в новой переменной для подключения
global $query_string;
$query_string = substr($filepath,$query_string_pos + 1);
$clean_file_path = substr($filepath,0,$query_string_pos);
//если query-строка отсутствует
} else {
$clean_file_path = $filepath;
}
//КОНЕЦ модифицированной части кода
//проверяем, указан ли путь к файлу и существует ли файл
if ($filepath != 'NULL' && file_exists(get_stylesheet_directory_uri() . "/" . $clean_file_path)){
//включаем буферизацию вывода для захвата вывода скрипта
ob_start();
//подключаем указанный файл
include(TEMPLATEPATH.$clean_file_path);
//присваиваем вывод файла переменной $content и очищаем буфер
$content = ob_get_clean();
//возвращаем $content
//возврат важен для того, чтобы вывод появился в правильном месте
//в контенте
return $content;
}
}
//регистрируем обработчик шорткода
add_shortcode('include', 'include_file');
//КОНЕЦ кода от amberpanther.com
//пример шорткода с query-строкой:
//[include filepath="/get-posts.php?format=grid&taxonomy=testing&term=stuff&posttype=work"]
Я настроил свой код на работу с URI стилей (чтобы он работал с дочерними темами и подобным), но вы можете легко изменить этот код для работы с любым другим местом (включая директории плагинов) или вообще удалить эту проверку и использовать полный путь при подключении файла. Вы даже можете добавить условие с триггерным символом в начале, который указывает на использование определенного пути в зависимости от первого символа имени файла, например, использование "#" для директории шаблона и т. д.
Я использую это для подключения файла get-posts.php, который находится в директории моего шаблона и форматирует вывод различных записей на основе ряда параметров, переданных в query-строке. Это избавляет меня от необходимости создавать специальные шаблоны, так как я могу подключить файл, передать ему формат, и он выведет записи с разметкой, указанной в файле get-posts.php.
Это также позволяет клиентам вставлять пользовательские типы записей в обычные записи блога в определенных форматах, что очень удобно.
Дайте мне знать, если вам что-то нужно уточнить.

Не следует использовать TEMPLATEPATH
или STYLESHEETPATH
. Вместо них используйте get_template/stylesheet_dir()
или их эквиваленты *_url()
для путей/URI.

ericissocial Огромное спасибо! Я сейчас подключу всё это и попробую, потом отпишусь о результатах.

Без проблем, тебе следует последовать рекомендации kaiser и использовать функционал GET_template вместо TEMPLATEPATH, который был в моём коде. Kaiser, спасибо за подсказку, я отредактирую код в своём ответе, когда буду не с телефона.

В решении, предложенном @adedoy, есть ошибка, так как переменная $slug не определена. Вот что сработало у меня:
function include_file($atts) {
$atts = shortcode_atts(
array(
'path' => 'NULL',
), $atts, 'include' );
ob_start();
get_template_part($atts['path']);
return ob_get_clean();
}
add_shortcode('include', 'include_file');
Использование: [include path="путь/от/корня"]

Хорошо, сначала я бы убрал буферизацию вывода.
Второе изменение:
include(TEMPLATEPATH.'/wp-content/themes/grainandmortar/inc_static/test.php');
Заменить на:
include( get_stylesheet_directory() . '/inc_static/test.php');
И наконец,
Прочитав документацию здесь: https://codex.wordpress.org/Shortcode_API
Вам нужно что-то возвращать. Если ваш test.php не выводит данные в формате, который можно вернуть, у вас будут проблемы.
Поэтому убедитесь, что test.php делает что-то вроде:
$output = "ДАННЫЕ"; // переменная, которую можно вернуть после include
// или
function test() {
// выполняем действия
return $stuff; // функция, возвращающая значение, которое можно вызвать после include
}
Затем после включения вашего файла test.php — вы просто возвращаете $output
или делаете что-то вроде return test();
.

Просто интересно узнать ваше мнение - почему не использовать буферизацию вывода для шорткодов?

Привет @mattLummus -- в конечном счете это вопрос подхода. Я считаю, что вам это НЕ НУЖНО для достижения цели, и вы мало что выигрываете, используя это. Кроме того, поддержу то, что сказано здесь: https://stackoverflow.com/questions/5454345/output-buffer-vulnerabilities-php -- "Буферизация вывода считается плохим решением, если используется для обхода старого доброго предупреждения Cannot send headers, output already started at... В таком случае буферизация вывода используется, чтобы скрыть плохой дизайн..."

Да, в этом конкретном случае это действительно выглядит как костыль. Обычно, когда мы используем буферизацию вывода, это не для обхода другой проблемы, а просто потому, что мы имеем дело с ситуацией, где у нас больше разметки, чем PHP-кода, и предпочитаем синтаксис с OB (возможность выходить из PHP и писать обычный HTML вместо кучи echo-вызовов и HTML в строках).
В любом случае, спасибо за ответ!

Я обнаружил, что исходный код include, написанный ребятами из AmberPanther, работал не очень хорошо, поэтому я нашел другой плагин для WordPress, который делает практически то же самое. Он называется Include Me, автор — Stefano Lissa. Использование довольно простое: вы указываете путь к файлу, начиная с корневой директории вашего сайта.
Например, на странице WordPress вы пишете:
[includeme file="wp-content/themes/your-theme/code/example-code.php"]
А в файле functions.php добавляете:
<?php
if (is_admin()) {
include dirname(__FILE__) . '/admin.php';
} else {
function includeme_call($attrs, $content = null) {
if (isset($attrs['file'])) {
$file = strip_tags($attrs['file']);
if ($file[0] != '/')
$file = ABSPATH . $file;
ob_start();
include($file);
$buffer = ob_get_clean();
$options = get_option('includeme', array());
if (isset($options['shortcode'])) {
$buffer = do_shortcode($buffer);
}
} else {
$tmp = '';
foreach ($attrs as $key => $value) {
if ($key == 'src') {
$value = strip_tags($value);
}
$value = str_replace('&', '&', $value);
if ($key == 'src') {
$value = strip_tags($value);
}
$tmp .= ' ' . $key . '="' . $value . '"';
}
$buffer = '<iframe' . $tmp . '></iframe>';
}
return $buffer;
}
// Функция должна быть определена ДО "add_shortcode", так как
// "add_shortcode" проверяет имя функции с помощью "is_callable".
add_shortcode('includeme', 'includeme_call');
}
Конечно, я также рекомендую просто установить плагин, чтобы получать обновления. https://wordpress.org/plugins/include-me/
