Все страницы сайта – это PHP шаблоны, содержащие HTML разметку с PHP тегами. Здесь будет рассмотрено создание шаблона страницы для отдельной записи – начиная от вордпресс цикла и до построения элементов навигации…
Содержание
Что представляет собой запись?
Каждая запись это отдельный представитель типа поста. Из коробки, есть 2 типа постов – страницы и записи; у каждой свои приколы по отображению – у страниц шаблоны для отображения, записей – форматы
Для создания шаблона страницы, в начало файла достаточно добавить комментарий
<?php // Template Name: TemplateName
с форматами постов все немного сложнее…
Чтобы активировать возможность выбора формата, в functions.php на экшн after_setup_theme функцию со следующим содержимым
<?php add_theme_support( 'post-formats', array( 'aside', 'image', 'video', 'quote', 'link', 'gallery', 'audio', ) );
Данный код содержит все допустимые форматы для постов; чтобы получить формат текущего поста используйте функцию get_post_format без аргументов, если ты внутри цикла(о нем позже), или с указанием ID поста.
При создании шаблона для своего типа записей – движок позволяет использовать только схему с форматами. По наименованию: для страниц с заголовком требований нет(если стандартный шаблон, без заголовка – page.php). Для постов и нестандартных типов записей – схема такова single-{post_type}.php, ну или single.php для всех типов кроме страниц(page).
WordPress циклы
Будь-то страница или любой другой тип записи(с условием, что он публичен – смотрите “Создаем свой тип записи. Метадата, роли пользователей, таксономии“) его вывод будет начат с цикла. В принципе, тип записей может быть и непубличным, но тогда его нужно будет принудительно доставать, что, я считаю, нехорошо. Итак, цикл(иногда его называют loop, поскольку это перевод) будет выглядеть так
<?php if (have_posts()) { while (have_posts()) { the_post(); // post content } }
Естественно, что в начале выводится шапка(get_header) и подвал(get_footer) в конце. Касательно наполнения цикла – принято подключать кусочек шаблона(отдельный файл) при помощи get_template_part($patth), содержащий разметку страницы.
Элементы страницы
Здесь я рассмотрю основные элементы сингл-поста, которые применимы как к записям, так и страницам и прочим типам.
Изображение записи
Для начала – нужно включить их поддержку – это делает следующий код
<?php add_action( 'after_setup_theme', 'themeslug_setup_theme' ); function themeslug_setup_theme(){ add_theme_support( 'post-thumbnails' ); }
После этого, на странице редактирования записи появиться такой метабокс
Теперь о том, как сохраняется загруженное изображение. По умолчанию, при сохранении , сохраняется оригинал и три нарезанных картинки из оригинала. Перейдя по “Settongs > Media” размеры этих изображений можно менять. Чтобы отключить нарезку достаточно выставить размеры в 0. Также, можно задать свой размер для кадрирования
<?php add_action( 'after_setup_theme', 'custom_size' ); function custom_size() { add_image_size( 'custom-size', 100, 100 ); }
Теперь мы имеем 2 варианта по получению установленного изображения; первый – это получение url на оригинал изображения; второй – получение всего img-тега
<?php // Получение url изображения $src = esc_url(get_the_post_thumbnail_url()); // вывод url изображения the_post_thumbnail_url(); // Получение img-тега $img = get_the_post_thumbnail(); // вывод img-тега the_post_thumbnail();
Приведенный выше код работает только внутри вордпресс-цикла, иначе, в качестве первого аргумента, следует указать ID поста. Но функции вывода работают только в цикле. Размеры кадров я упомянул в предыдущем абзаце к тому, что в данных функциях(получение во втором, вывод первым) можно указывать в виде аргумента название размеров. Стандартно full(оригинал), large(1024px*1024px), medium(300px*300px) и thumbnail(150px*150px). Также, вместо строки с названием размера, можно указать массив с шириной и высотой; при этом, при первой загрузке страницы с новым размером, будет создан и сохранен новый кадр.
Касательно получения и выведения img-тега. Последним аргументом в функцию можно передать массив атрибутов тега. Поскольку, в данной функции задается дефолтное значение этого аргумента, то задать можно только такие атрибуты – src, class и alt.
Таксономии
Будь-то стандартные, либо же кастомные таксономии, древовидные они или нет – вывод их одинаков
<?php $terms = wp_get_post_terms( $post_id, $taxonomy, $args );
Первые 2 аргумента понятны, третий это поля, которые будут возвращены; по умолчанию all, возможные значения – names ids.
В случаи, если нужны особые условия применить к получаемым данным, можно применить
<?php $terms = wp_get_object_terms($object_ids, $taxonomies, $args);
здесь $object_ids это ID записи, а вот на $args, пожалуй, поподробнее:
orderby -поле, по которому сортировать порядок вывода:
- поиск в полях терминов – term_id, name, slug, term_group;
- по полям таксономии терминов – id(поле term_taxonomy_id в таблице БД), description, parent, count(количество терминов в таксономии);
- среди полей таблицы term_relationships – term_order;
- по полям меты – meta_value_num(количеству полей meta_value) и по значению meta_key
Можно и вообще отключить сортировку установив значение в ‘none’. Ключ order устанавливает порядок сортировки(ASK/DESC).
Также, в этом массиве можно задать множество других параметров поиска. К примеру, наличие/отсутствие/равенство метаполей, вложенность, древовидность и т.д. Получаем ссылку на архив термина
<?php $url = esc_url(get_term_link( $term, $taxonomy ));
Контент и метадата
Для начала выведем заголовок записи
<?php // вывод the_title('<h1>', '</h1>'); // получение в переменную $title = esc_html(get_the_title());
В случаи с выведением на страницу, указывать аргументы не обязательно, но в такой записи заголовок будет обрамлен H1-тегом. Не много о том, почему не стоит вытягивать post_title с обьекта WP_Post – потому, что запись может быть личной или защищенной паролем; при правильном выводе эти статусы являются частью заголовка, при неправильном – этот функционал придется дублировать… а это плохо!
Что касается контента, там все аналогично(почти)
<?php // вывод the_content(); // получение в переменную $content = get_the_content();
Опять таки, можно вытянуть контент с обьекта WP_Post, но в функции get_the_content происходит ряд об робок другими фильтрами…
Следующее, это вывод/получение даты, а также ссылки на ее архив
<?php $format = get_option( 'date_format' ); //вывод the_date( $format, $before, $after ); // получение $date = the_date( $format, $before, $after, false ); // или $date = get_the_date( $format, $post ); // ссылка на архив $url = esc_url(get_day_link( $year, $month, $day ));
Здесь, как и в случаи с заголовком, $before и $after это текст(включая html) до и после даты.
Пару слов о метадате поста. Вся дополнительная информация к посту – это метадата. Чтоб ее достать достаточно знать метаключ за коим она храниться
<?php $metadata = get_post_meta($post_id, $metakey, true);
поскольку одинаковых метаключей к одной записи может быть много, то данные извлекаются в виде массива; если поле одно – можно сразу его извлечь, указав true третьим аргументом – иначе, по умолчанию, будет false.
Навигация
Под контентом поста принято делать ссылки на предыдущий и следующий посты. Делается это следующим кодом
<?php $nav = get_the_post_navigation($args);
Переменная будет содержать следующую разметку
<nav class="navigation post-navigation" role="navigation" aria-label="Posts"> <h2 class="screen-reader-text">Post navigation</h2> <div class="nav-links"> <div class="nav-previous"> <a href="{prevPostLink}" rel="prev">Prev Post Title</a> </div> <div class="nav-next"> <a href="{nextPostLink}" rel="next">Next Post Title</a> </div> </div> </nav>
Через аргумент функции моно кастомизировать только атрибуты class у и aria-label тега nav, а также то, что в ссылке. Для этого в массиве $args есть ключи prev_text(может содержать html-теги), next_text(тоже), aria_label и class.
Если же такой уровень кастомизации не достаточен и нужна своя разметка – делаем следующее: получаем а-теги
<?php $prevLink = get_previous_post_link(); $nextLink = get_next_post_link();
Комментарии
В вордпресс принято поключать комментарии таким образом
<?php if ( comments_open() || get_comments_number() ) : comments_template(); endif;
Здесь проверяется открытые ли комментарии у поста и их наличие. При выполнении хотя б одного условия – будут загружены стандартные форма комментирования и список комментов, которые можно перезаписать в файле comments.php темы.
Рекомендую сделать также, это избавит от некоторых проблем. Дальше, создаем файл comments.php и пишем в него.
Форма комментариев
Здесь ситуация похожа на ситуацию с навигацией: форму комментария строит отдельная функция.
<?php comment_form( $args, $post_id );
внутри цикла $post_id можно пропустить. При пустом $args получим следующий html
<div id="respond" class="comment-respond"> <h3 id="reply-title" class="comment-reply-title">Leave a Reply <small><a rel="nofollow" id="cancel-comment-reply-link" href="{cancelReplyLink}" style="display:none;">Cancel reply</a></small></h3> <form action="{actionLink}" method="post" id="commentform" class="comment-form" novalidate=""> <!-- if current user logged in --> <p class="logged-in-as"> <a href="{profileLink}" aria-label="Logged in as admin. Edit your profile.">Logged in as admin</a>. <a href="nonce=dc4f1aa958">Log out?</a> </p> <!-- endid --> <p class="comment-form-comment"> <label for="comment">Comment</label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required="required"></textarea> </p> <!-- if current user not logged in --> <p class="comment-form-author"> <label for="author">Name <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" required="required"> </p> <p class="comment-form-email"> <label for="email">Email <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" required="required"> </p> <p class="comment-form-url"> <label for="url">Website</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200"> </p> <p class="comment-form-cookies-consent"> <input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"> <label for="wp-comment-cookies-consent">Save my name, email, and website in this browser for the next time I comment.</label> </p> <!-- endif --> <p class="form-submit"> <input name="submit" type="submit" id="submit" class="submit" value="Post Comment"> <input type="hidden" name="comment_post_ID" value="10" id="comment_post_ID"> <input type="hidden" name="comment_parent" id="comment_parent" value="0"> </p> <input type="hidden" id="_wp_unfiltered_html_comment_disabled" name="_wp_unfiltered_html_comment" value="f6a52e0808"><script>(function(){if(window===window.parent){document.getElementById('_wp_unfiltered_html_comment_disabled').name='_wp_unfiltered_html_comment';}})();</script> </form> </div>
Но, в отличие от навигации, здесь можно провести полную кастомизацию через функцию. Для этого заполним массив $args:
- ключ fields – массив шаблонов(начиная с тега р), содержащий поля формы комментария за ключами author, email и url;
- comment_field – содержит шаблон, непосредственно, поля ввода комментария;
- must_log_in – текст для не залогиненных пользователей при обязательном логировании, чтоб оставить коммент;
- logged_in_as – текст для залогиненного пользователя;
- submit_field – шаблон поля отправки формы.
В принципе, для полной кастомизации этого достаточно, однако, в аргументе есть еще дополнительные поля для более тонкой настройки… и не только вида.
Немного о добавлении своих полей в форму комментирования: для добаления поля – фильтром comment_form_fields изменяй массив полей
<?php add_filter('comment_form_fields', 'custom_comment_form_field'); function custom_comment_form_field($comment_fields) { $custom_field['custom_field'] = '<p><label>My query<input name="my_query"></label></p>'; // insert $custom_field after name(index = 1) return array_merge( array_slice($comment_fields, 0, 2), $custom_field, array_slice($comment_fields, 2) ); }
после этого экшном wp_insert_comment нужно сохранить данное поле
<?php add_action('wp_insert_comment', 'wp_insert_custom_comment_field', 10, 2); function wp_insert_custom_comment_field($id, $comment) { if (isset($_POST['my_query'])) { update_comment_meta($id, 'my_query', sanitize_text_field($_POST['my_query'])); } }
Список комментариев
Следующая вещь, которая, по сути, есть продолжением формы комментариев – это список ранее оставленных комментариев. Он также выводится функцией
<?php wp_list_comments($args, $comments);
При использовании стандартной схемы аргумент $comments указывать не нужно. Иначе, $comments = get_comments() в котором нужно формировать свой массив аргументов. При пустом $args wp_list_comments выведет следующую разметку для каждого коммента
<li id="comment-1" class="comment even thread-even depth-1"> <article id="div-comment-1" class="comment-body"> <footer class="comment-meta"> <div class="comment-author vcard"> <img alt="" src="{avatar}" srcset="{avatar}" class="avatar avatar-32 photo" height="32" width="32" loading="lazy"> <b class="fn"><a href="https://wordpress.org/" rel="external nofollow ugc" class="url">A WordPress Commenter</a></b> <span class="says">says:</span> </div><!-- .comment-author --> <div class="comment-metadata"> <a href="{linkToComment}"> <time datetime="{commentTime}"> Comment Time </time> </a> <span class="edit-link"> <a class="comment-edit-link" href="{linkToEditComment}">Edit</a> </span> </div><!-- .comment-metadata --> </footer><!-- .comment-meta --> <div class="comment-content"> <p>Comment Text</p> </div><!-- .comment-content --> <div class="reply"> <a rel="nofollow" class="comment-reply-link" href="{linkToReply}" data-commentid="1" data-postid="1" data-belowelement="div-comment-1" data-respondelement="respond" data-replyto="Reply to A WordPress Commenter" aria-label="Reply to A WordPress Commenter">Reply</a> </div> </article><!-- .comment-body --> </li>
Здесь самый широкий, даже, наверное, излишний, способ кастомизации – и все доступно через функцию:
- max_depth – максимально разрешенная вложенность комментов;
- style – стиль вывода дерева – ul, ol(по умолчанию) или div. Данный аргумент имеет значение для вложенных комментариев, поскольку сама функция должна быть при вызове обнесенная контейнером отдельно;
- type – отображаемый тип комментариев;
- per_page – в случаи необходимости пагинации – количество комментариев на странице;
- page – страница пагинации коммента;
- avatar_size – размер аватара комментатора
- callback – функция-строитель каждого комментария, без закрывающего тега;
- end-callback – строитель закрывающего тега;
- walker экземпляр класса-строителя дерева комментариев.
Есть еще много ключей для “мелкой настройки” этой функции, но главное уже приведено. По поводу того, что функции открывающего и закрывающего тега разделены – тут, как и в меню, есть вложенность, и для ее реализации сделано так.
Сайдбар
Сайдбар – это место для вывода виджетов, виджет-зона. У нее, также как и у комментов, свой стандарт для выведения. В шаблоне страницы ставят такой код
<?php get_sidebar($slug);
данный код подключит sidebar.php из темы; если $slug не пустая строка, то подключит sidebar-{$slug}.php
<?php if (is_active_sidebar($slug)) { dynamic_sidebar($slug); }
$slug здесь это идентификатор виджет-зоны, который был указан при ее регистраци в функции register_sidebar().
Заключение
Рассмотрены все стандартные элементы шаблон страницы записи WordPress. О чем стоит упомянуть еще – так это о том, что в обертке каждого поста должны быть теги
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <!-- post content --> </article>
это анкор для ссылки в шапке. Считаю, что рассказал вам обо всех элементах сих страниц, так как дополнительные – это виджеты, вставляемые в сайдбар. И кстати, некоторые из этих элементов встречаются и на страницах других типов.