Шаблоны Произвольных Типов Записей из Папки Плагина?
Я хотел бы предоставить свой произвольный тип записи в виде плагина, чтобы люди могли использовать его без необходимости изменения папки темы. Но шаблоны произвольных типов записей -- такие как single-movies.php -- находятся в папке темы. Есть ли способ заставить WordPress проверять наличие single-movies.php в папке плагина? Подключить функцию через иерархию фильтров? Или использовать get_template_directory(); ?

Вы можете использовать хук фильтра single_template
.
/* Фильтруем single_template с нашей пользовательской функцией */
add_filter('single_template', 'my_custom_template');
function my_custom_template($single) {
global $post;
/* Проверяем шаблон для одиночной записи по типу поста */
if ( $post->post_type == 'НАЗВАНИЕ ТИПА ЗАПИСИ' ) {
if ( file_exists( PLUGIN_PATH . '/Custom_File.php' ) ) {
return PLUGIN_PATH . '/Custom_File.php';
}
}
return $single;
}

Это потрясающий ответ. Пожалуйста, поделитесь, где можно найти все доступные хуки шаблонов, такие как single_template.

@gowri Фильтр вызывается функцией get_query_template()
. Это переменный хук, поэтому первая часть {$type}_template
меняется в зависимости от параметра, передаваемого в эту функцию. Смотрите wp-includes/template.php для некоторых распространённых примеров.

Это руководство хорошо объясняет хук single_template. Как только вы разберётесь с хуками, комментарий @shea предлагает более простой подход по сравнению с ответом @Bainternet, используя add_filter( 'single-movies_template', 'my_custom_template' );
как в связанном руководстве. (Этот вопрос закрыт для новых ответов, поэтому я не могу добавить его отдельно.)

Вы можете заменить PLUGIN_PATH
на plugin_dir_path( __FILE__ )
, а затем убрать первый слеш из имени вашего файла. Полный путь будет выглядеть примерно так: return plugin_dir_path( __FILE__ ) . 'Custom_File.php';

PLUGIN_PATH вызывал ошибку, вот отличная статья, которая показывает, как это сделать, и у меня сработало сразу: https://wpsites.net/free-tutorials/load-single-template-from-plugin-for-different-post-types/

Обновленный ответ
Более чистая и короткая версия.
function load_movie_template( $template ) {
global $post;
if ( 'movie' === $post->post_type && locate_template( array( 'single-movie.php' ) ) !== $template ) {
/*
* Это запись типа 'movie'
* И шаблон 'single movie template' не найден в
* директориях темы или дочерней темы, поэтому загружаем его
* из директории нашего плагина.
*/
return plugin_dir_path( __FILE__ ) . 'single-movie.php';
}
return $template;
}
add_filter( 'single_template', 'load_movie_template' );
Старый ответ
Добавлена проверка наличия шаблона для пользовательского типа записи в папке темы к ответу @Brainternet.
function load_cpt_template($template) {
global $post;
// Это запись типа "my-custom-post-type"?
if ($post->post_type == "my-custom-post-type"){
// Путь к вашему плагину
$plugin_path = plugin_dir_path( __FILE__ );
// Название шаблона для одиночной записи пользовательского типа
$template_name = 'single-my-custom-post-type.php';
// Существует ли специфичный шаблон для моего типа записи в папке темы? Или его нет и в моем плагине?
if($template === get_stylesheet_directory() . '/' . $template_name
|| !file_exists($plugin_path . $template_name)) {
// Тогда возвращаем "single.php" или "single-my-custom-post-type.php" из директории темы.
return $template;
}
// Если нет, возвращаем шаблон из плагина.
return $plugin_path . $template_name;
}
// Это не мой пользовательский тип записи, ничего не делаем с $template
return $template;
}
add_filter('single_template', 'load_cpt_template');
Теперь пользователи плагина могут скопировать шаблон из вашего плагина в свою тему, чтобы переопределить его.
В этом примере шаблоны должны находиться в корневой директории как плагина, так и темы.

Использование locate_template
вместо get_stylesheet_directory
кажется мне более аккуратным решением (нашел здесь: http://code.tutsplus.com/tutorials/a-guide-to-wordpress-custom-post-types-creation-display-and-meta-boxes--wp-27645).

Обновленный ответ не сработал, принятый ответ (или ваш старый ответ) работает.

Хочу обратить внимание, что при использовании метода фильтрации крайне важно установить приоритет фильтра следующим образом:
add_filter('single_template', 'my_custom_template', 99);
Если этого не сделать, WordPress может попытаться выполнить повторную проверку после этого фильтра. Я потратил около 2 часов, разбираясь с этой проблемой.

В своих плагинах я обычно использую locate_template()
, что позволяет переопределять шаблоны плагина, копируя их в текущую тему:
function templateInclude(string $template): string
{
if (is_single() && get_query_var('post_type') === 'custom_post_type') {
$templates = [
'single-custom_post.php',
'templates/single-custom_post.php'
];
$template = locate_template($templates);
if (!$template) {
$template = __DIR__ . '/templates/single-custom_post.php';
}
}
return $template;
}
add_filter('template_include', 'templateInclude');
Теперь пользователь может переопределить шаблон плагина, скопировав его из папки плагина templates/single-custom_post.php
и разместив его либо непосредственно в корне, либо в папке templates
активной темы.
Полагаю, аналогичный подход можно использовать и с фильтром single_template
.

Существует гораздо лучший способ, который я использую в своих плагинах.
Как @campsjos упомянул здесь, вместо проверки существования файла, вы можете использовать
locate_template
, который проверит наличие переопределённого шаблона в теме. Это вполне очевидно.
function my_plugin_templates() {
if (is_singular('movie')) {
if (file_exists($this->template_dir . 'single-movie.php')) {
return $this->template_dir . 'single-movie.php';
}
}
}
Используйте хук фильтра template_include
для загрузки приведённого выше кода.
add_filter('template_include' , 'my_plugin_templates');

Благодаря этой странице я смог решить аналогичный вопрос для себя.
Для справки, вот что у меня получилось в итоге:
function pluginName_myposttype_single_template($single_template) {
$myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';
return get_post_type() === 'myposttype' && file_exists($myposttype_template) ? $myposttype_template : $single_template;
}
add_filter('single_template', 'pluginName_myposttype_single_template');
Фильтр {$type}_template не сработал в моем случае
function pluginName_myposttype_single_template($single_template) {
$myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';
if ( file_exists($myposttype_template) ) {
$single_template = $myposttype_template;
}
return $single_template;
}
add_filter('single-myposttype_template', 'pluginName_myposttype_single_template');

Этот вариант сработал для меня, попробуйте его. Спасибо.
Шаблоны загружаются в файл CPT, который находится по пути:
custom_plugin -> app -> cpt -> cpt_article.php
Шаблон расположен в:
custom_plugin -> app -> templates
add_filter( 'single_template', 'load_my_custom_template', 99, 1 );
function load_custom_templates($single_template) {
global $post;
if ($post->post_type == 'article' ) {
$single_template = trailingslashit( plugin_dir_path( __FILE__ ) .'app/templates' ).'single_article.php';
}
return $single_template;
}

Выше приведен отличный ответ, но проверка переменной $single позволяет шаблону переопределить шаблон, если он предоставлен темой/дочерней темой.
/* Фильтруем single_template с помощью нашей пользовательской функции */
add_filter('single_template', 'your_cpt_custom_template');
function your_cpt_custom_template( $single ) {
global $wp_query, $post;
/* Проверяем шаблон для одиночной записи по типу записи */
if ( !$single && $post->post_type == 'cpt' ) {
if( file_exists( plugin_dir_path( __FILE__ ) . 'single-cpt.php' ) )
return plugin_dir_path( __FILE__ ) . 'single-cpt.php';
}
return $single;
}

Это не проверяет наличие файла single-cpt.php в дочерней теме или основной теме. Проверяется только файл single.php, который всегда присутствует в любых темах.
