Добавление пользовательского шаблона страницы программным путем
Я пытаюсь добавить шаблон страницы из плагина, и мой файл шаблона находится в папке этого плагина. Возможно ли это? Вот мой код:
global $user_ID;
$new_post = array(
'post_title' => 'Тестовая страница шаблона',
'post_content' => 'Некоторый текст',
'post_status' => 'publish',
'post_date' => date('Y-m-d H:i:s'),
'post_author' => $user_ID,
'post_type' => 'page',
'post_category' => array(0)
);
$post_id = wp_insert_post($new_post);
if (!$post_id) {
wp_die('Ошибка создания страницы шаблона');
} else {
update_post_meta($post_id, '_wp_page_template', 'tp-file.php');
}
tp-file.php - это мой пользовательский шаблон страницы. Когда я помещаю этот файл в папку my-theme, он работает нормально, но я хочу сделать это с файлом из папки плагина, чтобы пользователям не приходилось копировать этот файл из папки плагина в папку шаблона. Возможно ли это? Есть какие-нибудь идеи?

Статья по ссылке движется в правильном направлении, но я упрощу её для вас.. ;)
add_filter( 'page_template', 'catch_plugin_template' );
function catch_plugin_template( $template ) {
if( 'tp-file.php' == basename( $template ) )
$template = WP_PLUGIN_DIR . '/yourpluginname/tp-file.php';
return $template;
}
Этот фильтр проверяет, установлен ли ваш специальный шаблон страницы для текущей страницы, и если да, обновляет путь, указывая на шаблон вашего плагина.
Просто убедитесь, что путь указан верно, иначе вы увидите ошибки подключения... :)
Дополнение #1
Первая проблема заключается в том, что WordPress проверяет любой шаблон, установленный как шаблон страницы, то есть он проверяет, находится ли файл в папке темы и является ли он валидным шаблоном. Если нет, он пропускает его и подключает более общий шаблон, например page.php...
Однако это не меняет того факта, что метаполе всё ещё хранит значение вашего кастомного шаблона, и также is_page_template( 'tp-file.php' )
будет корректно возвращать true, если использовать его вместо моего предыдущего условия, например..
// Фильтр шаблона страницы
add_filter('page_template', 'catch_plugin_template');
// Колбэк фильтра шаблона страницы
function catch_plugin_template($template) {
// Если tp-file.php установлен как шаблон
if( is_page_template('tp-file.php') )
// Обновляем путь (должен быть путь, используем WP_PLUGIN_DIR, а не WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Возвращаем
return $template;
}
ПРИМЕЧАНИЕ: Я изменил код, чтобы использовать WP_PLUGIN_DIR
, так как константа WP_PLUGIN_URL
не подходит для путей... (подключение файлов требует пути, а не URL).
Одна проблема, которую нельзя исправить, заключается в том, что при просмотре страницы из админки во время её редактирования, шаблон не будет отображаться как активный, и сохранение изменений может изменить активный шаблон. С этим мало что можно сделать, так как выпадающий список шаблонов страниц генерируется функцией, которая сканирует файлы темы, и нет хуков, которые позволили бы нам расширить этот список шаблонами из плагина.
Лично я бы предложил в качестве обходного решения сохранять дополнительное метаполе для каждой страницы, созданной с помощью вашего специального плагина, затем добавить хук на save_post
или wp_insert_post_data
и проверять, существует ли это метаполе. Если существует, также проверять, установлен ли шаблон страницы в tp-file.php
, и если нет, обновлять его до tp-file.php
. Дополнительное метаполе будет просто флагом, указывающим, какие страницы должны использовать шаблон вашего плагина.
Вот ваш плагин в самой базовой форме (да, я тестировал)... :)
<?php
/*
Plugin Name: TP Test Plugin
Plugin URI:
Description: TP Test Plugin
Version: 1.0.0
Author:
Author URI:
*/
global $wp_version;
if( version_compare( $wp_version, "2.9", "<" ) )
exit( 'Для этого плагина требуется WordPress 2.9 или новее. <a href="http://codex.wordpress.org/Upgrading_WordPress">Пожалуйста, обновитесь!</a>' );
// Добавляем колбэк в меню админки
add_action('admin_menu', 'create_tp_menu');
// Колбэк для добавления пунктов меню
function create_tp_menu() {
add_management_page('TP Test', 'TP Test', 'manage_options', 'tp-teste', 'wp_tp_test_fnc' );
}
function wp_tp_test_fnc() {
//include('tp-form-file.php');
if( !empty( $_POST['tp_name'] ) ) {
$tp_name = $_POST['tp_name'];
global $user_ID;
$new_post = array(
'post_title' => $tp_name,
'post_content' => 'Некоторый текст',
'post_status' => 'publish',
'post_date' => date('Y-m-d H:i:s'),
'post_author' => $user_ID,
'post_type' => 'page',
);
$post_id = wp_insert_post($new_post);
if( !$post_id )
wp_die('Ошибка при создании страницы шаблона');
else
update_post_meta( $post_id, '_wp_page_template', 'tp-file.php' );
/*
$pt = get_page_templates();
$pt['TP file test'] = WP_PLUGIN_URL . '/tp-test/tp-file.php';
echo "<pre>";
print_r($pt);
echo "</pre>";
*/
}
?>
<fieldset style="margin: 50px 100px;background-color: #cccccc;padding: 30px;border: 1px solid #ccc">
<legend style="background-color: #ccccff;padding: 20px;font-weight: bold;font-size: 18px">Создать страницу шаблона</legend>
<form name="frm_main" action="" method="POSt">
<input class="text" type="text" name="tp_name" size="50" />
<br />
<input class="button" type="submit" value="Создать страницу шаблона" name="btn_submit" />
</form>
</fieldset>
<?php
}
// Фильтр шаблона страницы
add_filter('page_template', 'catch_plugin_template');
// Колбэк фильтра шаблона страницы
function catch_plugin_template($template) {
// Если tp-file.php установлен как шаблон
if( is_page_template('tp-file.php') )
// Обновляем путь (должен быть путь, используем WP_PLUGIN_DIR, а не WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Возвращаем
return $template;
}
Надеюсь, это поможет прояснить ситуацию.. :)

Спасибо @t31os, я попробовал это, но это не сработало, затем я нашел это http://adambrown.info/p/wp_hooks/hook/page_template, что устарело, есть другие идеи?

Я также попробовал что-то вроде этого, но это не сработало : $pt = get_page_templates(); $pt['TP testing'] = WP_PLUGIN_URL . '/tp-test/tp-file.php';

У меня это работает прекрасно... Мне нужно больше деталей, чем просто "это не сработало".

Похоже, что шаблонные файлы не включены в подпапке. Я обнаружил это в функции get_page_templates в файле theme.php. Есть другие идеи?

Это не имеет значения, предоставленный мной код будет работать нормально, при условии что путь указан правильно и у запрашиваемой страницы установлено _wp_page_template
в значение tp-file.php
... Я только что перепроверил снова, чтобы убедиться, и снова подтвердил, что код работает (мне нужно увидеть больше вашего кода, если вы хотите, чтобы я помог разобраться, почему он не работает в вашей настройке).

Спасибо за ваше время, мой код не менялся, единственное - я добавил ваш код в мой основной файл плагина, посмотрите здесь: http://pastebin.com/sNR9s0sP

Хорошо, но что происходит, когда вы загружаете страницу, у которой _wp_page_template
установлен в tp-file.php
? Вы видите ошибку включения, пустую страницу или что-то ещё? Помогите мне помочь вам... ;)

Я вижу "Какой-то текст", как на обычной странице, и если я перехожу в админку, то вижу, что шаблон страницы установлен на стандартный, и моего файла шаблона нет в списке

Я собираюсь лечь спать в ближайшие минуты, но завтра я уточню этот вопрос для вас. Пока метаполе _wp_page_template
остается правильно установленным, всё должно работать, независимо от того, что оно не отображается в админке (что ожидаемо — объясню в обновлении ответа завтра).

Хм, это странно, код не работает, когда форма в отдельном файле, но если она вместе, то всё работает.

Попробуй указать action в твоей форме, например action="<?php admin_url( '/?page=tp-teste' ) ?>"
, чтобы убедиться, что она отправляется на страницу твоего плагина корректно.

Фильтр page_template
теперь считается устаревшим. (http://adambrown.info/p/wp_hooks/hook/page_template)
Вместо него рекомендуется использовать single_template
(или archive_template
для архивных шаблонов).
На основе ответа @t31os:
// Фильтр шаблона страницы
add_filter('single_template', 'catch_plugin_template');
// Функция обратного вызова для фильтра шаблона страницы
function catch_plugin_template($template) {
// Если установлен шаблон tp-file.php
if( is_page_template('tp-file.php') )
// Обновляем путь (должен быть путь, используйте WP_PLUGIN_DIR, а не WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Возвращаем
return $template;
}

если фильтр single_template
не сработал, можно использовать этот фильтр:
add_filter('template_include', 'catch_plugin_template');
взято отсюда: https://www.pradipdebnath.com/2019/08/17/how-to-add-page-template-from-plugin-in-wordpress/

Не уверен, что он устарел, просто изменился с версии 4.7. https://developer.wordpress.org/reference/hooks/type_template/.The аргумент пуст, если тема(ы) не предоставляют шаблон, а не если страница выбрала (сохранила) его в базе данных из выпадающего списка.

Одна проблема, и это не то, что можно исправить, заключается в том, что при просмотре страницы из админки, во время её редактирования, шаблон не будет отображаться как активный, и сохранение изменений может, конечно же, изменить активный шаблон. Здесь мало что можно сделать - выпадающий список шаблонов страниц генерируется функцией, которая сканирует файлы темы, и нет хуков, которые позволили бы нам расширить этот список шаблонами из плагина.
На самом деле я нашёл хук в другой теме, который делает именно это:
WordPress: Можно ли программно создавать шаблоны страниц?
Для удобства вставляю код здесь:
CONST CUSTOM_PAGE_TEMPLATES = array(
array('slug' => 'home', 'label' => 'Главная'),
array('slug' => 'content-page', 'label' => 'Страница контента'),
array('slug' => 'ordering', 'label' => 'Оформление заказа'),
array('slug' => 'reviews', 'label' => 'Отзывы')
);
/**
* Добавляет шаблоны страниц без файлов в выпадающий список шаблонов
*/
add_filter('theme_page_templates', function($page_templates, $wp_theme, $post) {
foreach(CUSTOM_PAGE_TEMPLATES as $template) {
// Добавляем, если ещё не существует
if (!isset($page_templates[$template['slug']])) {
$page_templates[$template['slug']] = $template['label'];
}
}
return $page_templates;
}, PHP_INT_MAX, 3);
Надеюсь, это кому-то поможет.
