одиночний - {$ post_type} - {slug} .php для користувацьких типів публікацій


20

Моя улюблена частина ієрархії шаблонів Wordpress - це можливість швидко створювати файли шаблонів для сторінок за допомогою слупок, не потребуючи редагування сторінки в Wordpress для вибору шаблону.

Наразі ми можемо це зробити:

page- {slug} .php

Але я хотів би це зробити:

одиночний {{post_type} - {slug} .php

Так що, наприклад, для типу публікації, що називається review, я міг зробити шаблон для публікації під назвою "Мій великий відгук" вsingle-review-my-great-review.php

Хтось це налаштовував раніше? single-{post_type}-{slug}.php


Ніколи раніше не використовували таку настройку, але якщо вона занадто складна, чому б просто не створити файл шаблону та пов’язати його з відповідним оглядом.
Шейн

WP 3.4 автоматично завантажується single-{post_type}-{slug}.php, тому оновлення до WP 3.4 - це інший варіант.
yitwail

Відповіді:


19

А) Основа в ядрі

Як видно з пояснення ієрархії шаблонів Codex , single-{$post_type}.phpвже підтримується.


Б) Розширення основної Ієрархії

Тепер із задоволенням є деякі фільтри та гачки всередині /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • І: специфічний фільтр всередині з get_query_template( $type, ... )назвою:"$type}_template"

В.1) Як це працює

  1. Усередині файл завантажувач шаблон, шаблон завантажується на запиті вару / WP_Query умовно: is_*().
  2. Потім умовне запускає (у випадку "єдиного" шаблону): is_single() && $template = get_single_template()
  3. Це спрацьовує тоді get_query_template( $type, $templates ), де $typeєsingle
  4. Потім у нас є "{$type}_template"фільтр

В) Розв’язання

Оскільки ми хочемо лише розширити ієрархію одним шаблоном, який завантажується перед фактичним "single-{$object->post_type}.php"шаблоном, ми перехопимо ієрархію та додамо новий шаблон до початку масиву шаблонів.

// Extend the hierarchy
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // New 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Like in core
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Now we add the filter to the appropriate hook
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

ПРИМІТКА: (Якщо ви хочете використовувати щось інше, ніж об'єкт за замовчуванням $slug. Просто використовуйте все, що вам потрібно від глобального (object) $post.

Квитки на Trac

Оскільки вищезазначений підхід наразі не підтримується (ви можете фільтрувати абсолютно розташований шлях таким чином), ось список квитків на траси:


Я хочу перевірити це, але, схоже, у вашому рядку add_filter наприкінці щось не вистачає.
суперпер

@supertrue Хороший улов. :) Знайдено ще одне відсутнє )всередині фільтра. Виправлено. Можливо, ви хочете обміняти тире з підкресленням перед слизом всередині шаблону. Просто, щоб суфікс краще виділявся при перегляді шаблонів.
кайзер

Викликає цю помилку на сайті: Попередження: array_unshift () [function.array-unshift]: Першим аргументом повинен бути масив у [рядок, що містить array_unshift]
supertrue

Добре, але тоді щось інше перехоплює основні шаблони. Функція прекрасно працює і $templatesє масивом. Дивіться основні функції цієї пастини (немає терміну придатності). Переконайтесь, що ви протестували це за допомогою установки без плагінів та теми за замовчуванням. Потім активуйте один за одним і подивіться, чи помилка все-таки виникає.
кайзер

Так, я налагодив це, я отримую остаточний абсолютний шлях першого знайденого шаблону назад як рядок. Мені доведеться поговорити з якимось основним розробником про це, перш ніж змінювати відповідь. Також: Я щось переплутав: slugдоступний лише для термінів та таксономій. Ви повинні замінити $post->post_nameтим, що відповідає вашій структурі постійної посилання. В даний час немає способу зробити це автоматично для всіх випадків із завантаженням та заміною шляху залежно від вашої структури perma та переписання. Очікуйте ще одного оновлення.
кайзер

4

Дотримуючись зображення Ієрархії шаблонів , я не бачу такої опції.

Тож ось як би я пішов про це:

Рішення 1 (найкраще на мій погляд)

Створіть файл шаблону та пов’яжіть його з оглядом

 <?php
 /*
 Template Name: My Great Review
 */
 ?>

Додавши файл php шаблону у свій тематичний каталог, він відображатиметься як параметр шаблону на сторінці редагування вашої публікації.

Рішення 2

Можливо, цього можна досягти за допомогою template_redirectгачка.

У файлі function.php:

 function my_redirect()
 {
      global $post;

      if( get_post_type( $post ) == "my_cpt" && is_single() )
      {
           if( file_exists( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' ) )
           {
                include( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' );
                exit;
           }
      }
 }
 add_action( 'template_redirect', 'my_redirect' );

EDIT

Додано file_existsчек


Чому ти exit;там?
кайзер

@kaiser Повинен бути в будь-якому підручнику, який я виконував у той час, якщо це не потрібно, я його видалю.
Шейн

1
@kaiser: exit()Необхідно, щоб не завантажувати шаблон за замовчуванням.
scribu

Рішення 1 працюватиме лише для сторінок, а не дописів.
IXN

2

Верхня відповідь (від 4 років тому) більше не працює, але WordPress кодекс має рішення тут :

<?php
function add_posttype_slug_template( $single_template )
{
    $object = get_queried_object();
    $single_postType_postName_template = locate_template("single-{$object->post_type}-{$object->post_name}.php");
    if( file_exists( $single_postType_postName_template ) )
    {
        return $single_postType_postName_template;
    } else {
        return $single_template;
    }
}
add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
?>

1

Використовуйте шаблони сторінок

Іншим підходом до масштабованості буде дублювання функцій випадаючого шаблону сторінки на pageтип публікації для вашого спеціального типу публікації.

Код багаторазового використання

Копіювання коду не є хорошою практикою. Понаднормовий процес може спричинити сильний розрив кодової бази, тоді як розробнику дуже важко керувати. Замість створення шаблону для кожного окремого слизу вам, швидше за все, знадобиться шаблон "один на багато", який можна повторно використовувати замість одного-до-одного "пост-шаблон".

Кодекс

# Define your custom post type string
define('MY_CUSTOM_POST_TYPE', 'my-cpt');

/**
 * Register the meta box
 */
add_action('add_meta_boxes', 'page_templates_dropdown_metabox');
function page_templates_dropdown_metabox(){
    add_meta_box(
        MY_CUSTOM_POST_TYPE.'-page-template',
        __('Template', 'rainbow'),
        'render_page_template_dropdown_metabox',
        MY_CUSTOM_POST_TYPE,
        'side', #I prefer placement under the post actions meta box
        'low'
    );
}

/**
 * Render your metabox - This code is similar to what is rendered on the page post type
 * @return void
 */
function render_page_template_dropdown_metabox(){
    global $post;
    $template = get_post_meta($post->ID, '_wp_page_template', true);
    echo "
        <label class='screen-reader-text' for='page_template'>Page Template</label>
            <select name='_wp_page_template' id='page_template'>
            <option value='default'>Default Template</option>";
            page_template_dropdown($template);
    echo "</select>";
}

/**
 * Save the page template
 * @return void
 */
function save_page_template($post_id){

    # Skip the auto saves
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    elseif ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;
    elseif ( defined( 'DOING_CRON' ) && DOING_CRON )
        return;

    # Only update the page template meta if we are on our specific post type
    elseif(MY_CUSTOM_POST_TYPE === $_POST['post_type'])
        update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
}
add_action('save_post', 'save_page_template');


/**
 * Set the page template
 * @param string $template The determined template from the WordPress brain
 * @return string $template Full path to predefined or custom page template
 */
function set_page_template($template){
    global $post;
    if(MY_CUSTOM_POST_TYPE === $post->post_type){
        $custom_template = get_post_meta($post->ID, '_wp_page_template', true);
        if($custom_template)
            #since our dropdown only gives the basename, use the locate_template() function to easily find the full path
            return locate_template($custom_template);
    }
    return $template;
}
add_filter('single_template', 'set_page_template');

Це трохи пізня відповідь, але я вважав, що це буде цінним, оскільки ніхто в Інтернеті не підтвердив цей підхід, наскільки я можу сказати. Сподіваюся, це допоможе комусь вийти.


1

У моєму випадку у мене є власні типи публікацій альбомів і відстежень, пов’язані систематикою альбому. Мені хотілося використовувати різні шаблони для публікацій альбомів та треків залежно від їх систематики.

Виходячи з відповіді Кайзера вище, я написав цей код. Це добре працює.
Примітка. Мені не потрібно було додавання ().

// Add an additional template option to the template hierarchy
add_filter( 'single_template', 'add_albumtrack_taxslug_template', 10, 1 );
function add_albumtrack_taxslug_template( $orig_template_path )
{
    // at this point, $orig_template_path is an absolute located path to the preferred single template.

    $object = get_queried_object();

    if ( ! (
        // specify another template option only for Album and Track post types.
        in_array( $object->post_type, array( 'gregory-cpt-album','gregory-cpt-track' )) &&
        // check that the Album taxonomy has been registered.
        taxonomy_exists( 'gregory-tax-album' ) &&
        // get the Album taxonomy term for the current post.
        $album_tax = wp_get_object_terms( $object->ID, 'gregory-tax-album' )
        ))
        return $orig_template_path;

    // assemble template name
    // assumption: only one Album taxonomy term per post. we use the first object in the array.
    $template = "single-{$object->post_type}-{$album_tax[0]->slug}.php";
    $template = locate_template( $template );
    return ( !empty( $template ) ? $template : $orig_template_path );
}

Тепер я можу створювати шаблони з ім'ям single-gregory-cpt-track-tax-serendipity.php та single-gregory-cpt-album-tax-serendipity.php та WP використовуватимуть їх автоматично; "tax-serendipity" - слуга для першого терміна таксономії альбому.

Для довідки, гачок фільтра 'single_template' оголошено у:
/wp-includes/theme.php:get_query_template()

Дякую Кайзер за зразок коду.

Ура, Григорі


Привіт Грег - ласкаво просимо до WPSE. Будь ласка, публікуйте відповіді лише як відповіді на запитання, а не подальші запитання. Якщо у вас є запитання, на яке не знайдено відповіді, і воно занадто велике для коментаря, будь ласка, відкрийте інше питання :)
Стівен Харріс

1
питання про рядок / масив видалено :-)
Грегорі

1
"Дякую Кайзер за зразок коду." - Ласкаво просимо.
кайзер

це працює для вас? Перш за все, у вашому коді не слід коментувати "$ template". Я думаю, що замість "$ album_tax [0] -> slug" має бути "$ object-> post_name", чи не так?
gregmatys

виправлено рядок шаблону $. Дякую. $ object-> post_name? ні. це поверне слизьку публікації, але мені потрібен альбом альбому, з яким пов’язаний пост.
Григорій

0

Оновлення коду Brians, я виявив, що коли не використовувалося спадне поле, параметр шаблону "за замовчуванням" зберігався у wp_page_template, завдяки чому він намагався знайти шаблон, званий за замовчуванням. ця зміна просто перевіряє параметр "за замовчуванням" при збереженні та видаляє замість цього повідомлення мета (корисно, якщо ви змінили параметр шаблону назад на типовий)

elseif (MY_CUSTOM_POST_TYPE === $ _POST ['post_type']) {

if (esc_attr ($ _ POST ['_ wp_page_template']) === "за замовчуванням"):
    delete_post_meta ($ post_id, '_wp_page_template');
ще:
    update_post_meta ($ post_id, '_wp_page_template', esc_attr ($ _ POST ['_ wp_page_template']));
ендіф;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.