Файл single.php: как настроить вывод отдельной записи в WordPress

Раздел: Веб-разработка -> Темы WordPress

Как работает single.php в WordPress: от базового шаблона до расширенных сценариев

Файл single.php отвечает за отображение отдельной записи (поста) на сайте WordPress. Он входит в иерархию шаблонов и вызывается, когда пользователь переходит по постоянной ссылке на конкретную публикацию. Понимание структуры этого файла позволяет гибко управлять выводом контента, добавлять метаданные, менять оформление в зависимости от типа записи или рубрики.

Как построить классический шаблон отдельной записи?

Самый надёжный способ - использовать стандартный цикл WordPress (Loop). Внутри цикла вызываются теги шаблона для заголовка, контента, миниатюры, мета-информации. Ниже приведён минимальный рабочий код файла single.php.


<?php get_header(); ?>

<main id="primary" class="site-main">
  <?php
  while ( have_posts() ) :
    the_post();
    ?>
    <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
      <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
        <div class="entry-meta">
          <?php
          printf(
            esc_html__( 'Опубликовано %s автором %s', 'textdomain' ),
            get_the_date(),
            get_the_author()
          );
          ?>
        </div>
      </header>

      <?php if ( has_post_thumbnail() ) : ?>
        <div class="post-thumbnail">
          <?php the_post_thumbnail( 'large' ); ?>
        </div>
      <?php endif; ?>

      <div class="entry-content">
        <?php the_content(); ?>
        <?php
        wp_link_pages( array(
          'before' => '<div class="page-links">' . esc_html__( 'Страницы:', 'textdomain' ),
          'after'  => '</div>',
        ) );
        ?>
      </div>

      <footer class="entry-footer">
        <?php the_tags( '<span class="tags-links">' . esc_html__( 'Метки:', 'textdomain' ) . ' ', ', ', '</span>' ); ?>
        <?php the_category( ', ', '<span class="cat-links">', '</span>' ); ?>
      </footer>
    </article>

    <?php
    // Если комментарии открыты, выводим их
    if ( comments_open() || get_comments_number() ) :
      comments_template();
    endif;
    ?>

  <?php endwhile; // end of the loop. ?>
</main>

<?php get_sidebar(); ?>
<?php get_footer(); ?>
  

Wp single php (файл single.php в wordpress)

Типичные проблемы и ошибки:

  • Не сбрасывается цикл после основного запроса. Если после while используется второй запрос (например, WP_Query), необходимо вызвать wp_reset_postdata(), иначе могут появиться некорректные данные на странице.
  • Использование the_ID() вне цикла. Тег the_ID() выводит ID только внутри цикла. Для получения ID за пределами цикла используйте get_the_ID().
  • Отсутствие fallback для comments_template(). Если тема не поддерживает комментарии, вызов без проверки приведёт к ошибке. Всегда проверяйте comments_open().
  • Проблемы с пагинацией контента. Если запись разбита на несколько страниц тегом <!--nextpage-->, обязательно используйте wp_link_pages() для навигации.

Этот вариант подходит для большинства стандартных блогов. Он использует встроенные функции WordPress, легко переопределяется в дочерних темах и полностью соответствует кодексу.

Как разделить вывод для разных типов записей с помощью get_template_part?

Если в теме используются произвольные типы записей (Custom Post Types), удобно разнести шаблоны их отображения в отдельные файлы и подключать их через get_template_part(). Это позволяет держать single.php чистым и избегать условий.


<?php
$post_type = get_post_type();
get_template_part( 'template-parts/single/content', $post_type );
?>
  

Wp blog header php (шаблоны header в wordpress)

В папке template-parts/single/ создаются файлы content-post.php (для стандартных записей), content-portfolio.php (для портфолио) и т.д. Каждый из них содержит свою разметку.

Возможные ошибки:

  • Если файл content-{type}.php отсутствует, get_template_part() не вызовет ошибку, но ничего не выведет. Рекомендуется создавать файл-заглушку content.php как fallback.
  • Путь к файлу должен указываться без расширения и без ведущей косой черты.

Как модифицировать вывод с помощью условных тегов внутри single.php?

Иногда требуется изменить блоки в зависимости от рубрики, метки или пользовательских данных. Условные теги (in_category(), has_tag(), is_single()) позволяют это сделать без создания дополнительных шаблонов.


<?php if ( in_category( 'news' ) ) : ?>
  <div class="news-badge">Новость</div>
<?php endif; ?>

<?php the_content(); ?>

<?php if ( has_tag( 'sale' ) ) : ?>
  <p class="sale-notice">Товар участвует в акции!</p>
<?php endif; ?>
  

Распространённые сложности:

  • Условные теги работают только после установки глобального объекта $post (после вызова the_post()). Использование их до цикла приведёт к непредсказуемым результатам.
  • При использовании нескольких условных проверок код может стать трудночитаемым. В таких случаях лучше вынести логику в отдельный файл или использовать шаблоны с get_template_part().

Как добавить кастомные поля и метабоксы в шаблон записи?

Для отображения произвольных полей (через Advanced Custom Fields или встроенную функцию get_post_meta()) достаточно разместить вызов внутри цикла.


<?php
$price = get_post_meta( get_the_ID(), 'price', true );
if ( $price ) : ?>
  <div class="product-price">Цена: <?php echo esc_html( $price ); ?> руб.</div>
<?php endif; ?>
  

Типичные проблемы:

  • Обращение к мета-полям до вызова the_post() (или без указания ID) вернёт данные предыдущей записи. Всегда используйте get_the_ID() внутри цикла.
  • Не забывайте экранировать вывод мета-полей с помощью esc_html() или esc_attr() для защиты от XSS.

Как настроить отображение комментариев с поддержкой вложенности?

По умолчанию comments_template() подключает файл comments.php из папки темы. Можно передать аргументы для кастомизации.


<?php
if ( comments_open() || get_comments_number() ) :
  $args = array(
    'style'       => 'div',
    'callback'    => 'my_theme_comment',
    'max_depth'   => 3,
  );
  comments_template( '', true, $args );
endif;
?>
  

Распространённые ошибки:

  • Если файл comments.php отсутствует, WordPress подключит стандартный шаблон. Но для полного контроля его нужно создать.
  • Передача третьего параметра ($args) в comments_template() доступна начиная с WordPress 5.5. Для старых версий используйте фильтр comments_template_query_args.

Расширенные примеры использования single.php

Пример 1. single.php для произвольного типа записи «portfolio» с таксономиями и ACF

В этом примере выводятся данные портфолио: изображение проекта, описание, клиент (поле ACF) и список технологий (таксономия).

Пример

<?php
/* single-portfolio.php */
get_header();
while ( have_posts() ) : the_post();
  $client = get_field( 'client' );
  $url    = get_field( 'project_url' );
?>
  <article id="post-<?php the_ID(); ?>" <?php post_class( 'portfolio-item' ); ?>>
    <?php the_post_thumbnail( 'portfolio-full' ); ?>
    <h2 class="portfolio-title"><?php the_title(); ?></h2>
    <div class="portfolio-meta">
      <?php if ( $client ) : ?>
        <span class="client">Клиент: <?php echo esc_html( $client ); ?></span>
      <?php endif; ?>
      <?php
      $techs = get_the_term_list( get_the_ID(), 'technology', 'Технологии: ', ', ' );
      if ( $techs ) : ?>
        <span class="technologies"><?php echo $techs; ?></span>
      <?php endif; ?>
    </div>
    <div class="portfolio-content"><?php the_content(); ?></div>
    <?php if ( $url ) : ?>
      <a href="<?php echo esc_url( $url ); ?>" class="btn" target="_blank">Открыть проект</a>
    <?php endif; ?>
  </article>
<?php endwhile;
get_footer();
?>

Результат: страница отдельного проекта портфолио с изображением, описанием, клиентом, технологиями и ссылкой. Файл single-portfolio.php автоматически используется для записей типа «portfolio» благодаря иерархии шаблонов.

Пример 2. Пагинация для записей, разбитых на части (nextpage)

Если запись содержит тег <!--nextpage-->, WordPress делит её на несколько страниц. Для корректной навигации используйте wp_link_pages() внутри цикла.

Пример

<?php the_content(); ?>
<?php
wp_link_pages( array(
  'before'      => '<div class="page-links">' . esc_html__( 'Страницы:', 'textdomain' ),
  'after'       => '</div>',
  'link_before' => '<span class="page-number">',
  'link_after'  => '</span>',
  'pagelink'    => '%',
) );
?>

Результат: под контентом появляются ссылки вида «Страницы: 1 2 3». По умолчанию wp_link_pages() выводит только номера страниц. Для более сложной навигации (предыдущая/следующая) добавьте аргумент 'next_or_number' => 'both'.

Пример 3. Динамическая подгрузка похожих записей через WP_Query

После основного цикла можно вывести блок «Похожие записи», выбрав записи из тех же рубрик.

Пример

<?php
$categories = wp_get_post_categories( get_the_ID() );
if ( $categories ) {
  $args = array(
    'category__in'   => $categories,
    'post__not_in'   => array( get_the_ID() ),
    'posts_per_page' => 3,
    'orderby'        => 'rand',
  );
  $related = new WP_Query( $args );
  if ( $related->have_posts() ) : ?>
    <h3>Похожие записи</h3>
    <ul>
      <?php while ( $related->have_posts() ) : $related->the_post(); ?>
        <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
      <?php endwhile; ?>
    </ul>
  <?php endif;
  wp_reset_postdata();
}
?>

Результат: внизу страницы отображается блок из трёх случайных записей из тех же категорий. Важно: вызов wp_reset_postdata() восстанавливает глобальный объект $post, иначе последующий код может работать неправильно.

Пример 4. Создание собственного шаблона через фильтр template_include

Иногда нужно подменить файл single.php на лету, например, для записей с определённым ID или значением произвольного поля.

Пример

// functions.php
add_filter( 'template_include', 'my_custom_single_template' );
function my_custom_single_template( $template ) {
  if ( is_single() && get_post_meta( get_the_ID(), '_featured', true ) == 'yes' ) {
    $new_template = locate_template( array( 'single-featured.php' ) );
    if ( $new_template ) {
      return $new_template;
    }
  }
  return $template;
}

Теперь для записей с мета-полем _featured = yes будет использоваться файл single-featured.php. Это даёт гибкость без изменения иерархии шаблонов.

Пример 5. Интеграция Schema.org разметки в single.php

Для SEO можно добавить микроразметку Article. Обёртка с атрибутами itemscope и itemtype.

Пример

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?> itemscope itemtype="http://schema.org/Article">
  <meta itemprop="mainEntityOfPage" content="<?php the_permalink(); ?>" />
  <span itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="<?php echo esc_attr( get_the_author() ); ?>" />
  </span>
  <meta itemprop="datePublished" content="<?php echo get_the_date( 'c' ); ?>" />
  <meta itemprop="dateModified" content="<?php echo get_the_modified_date( 'c' ); ?>" />
  <div itemprop="image" itemscope itemtype="http://schema.org/ImageObject">
    <?php the_post_thumbnail( 'large', array( 'itemprop' => 'url' ) ); ?>
  </div>
  <div itemprop="articleBody"><?php the_content(); ?></div>
</article>

Результат: страница записи содержит структурированные данные, которые помогают поисковым системам лучше понимать контент. Проверить разметку можно через тестер Google Rich Results.

Файл single.php в WordPress - comments

En
Wp single php (php)