This article introduces a very important concept in WordPress theme development: the WordPress `get_template_part` function. It’s one of the many important concepts in all of WordPress theme development. (We have a full free course on the topic, check it out.)
This content is amazing, because it’s not just one of our normal articles: It’s a sample chapter from our “learn WordPress development” guide Up and Running, our comprehensive summary of all the information a person needs to be rolling as a WordPress developer.
If you like this chapter, check out Up and Running. There’s about 40 more chapters where this one came from. It’s the best guide to WordPress development out there.
In WordPress, get_template_part()
is a helpful way to avoid duplication and repetition within a WordPress theme. Use get_template_part()
for any template code that you would otherwise end up copying-and-pasting. This chapter covers how WordPress’s get_template_part()
function works, why
get_template_part
matters for WordPress themes, and how to use it in your own theme development.
In this example, WordPress will load up index.php
, and it will run as if the contents of content.php
were inside it. You can think of it as being WordPress loading in the “sub-template” completely in the line where get_template_part()
was called. This lets us avoid rewriting (or maintaining) all the same code around the various files of our WordPress theme.
Breaking this one file into two has a number of advantages:
- Both
index.php
andcontent.php
are now compact and readable. - The two files now have distinct responsibilities:
index.php
contains mostly logic, andcontent.php
contains mostly presentational HTML/PHP templating code. - The major advantage: the code in
content.php
can be reused by other template files, likehome.php
, simply by having those files also callget_template_part( 'content' )
. This cuts down on the overall bulkiness of the theme, and it prevents repetition: if you want to change something aboutcontent.php
, you only change it once, and the changes propagate everywhere.
Based on this code, WordPress will look for the following files, in order:
- In the child theme:
first-second.php
- In the parent theme:
first-second.php
- In the child theme:
first.php
- In the parent theme:
first.php
Will look for a file named firstargument-secondargument.php
—both arguments, combined and separated by a hyphen. If this file isn’t found, WordPress will fall back to simply firstargument.php
. In both cases, it will look for these files first in the child theme (if one exists), then in the parent theme.
First, the default PHP functions do not have the “two arguments with fallbacks” structure of get_template_part()
, as covered above. This means that a file moving, or not having an expect fall back will just break. That’s bad.
The second, and more important reason is child themes. For a child theme to modify a template part file—for example, a child theme that creates its own version of content.php
—require
simply won’t work. It’s not “child theme aware” which is a really important thing for WordPress themes.
With get_template_part()
, the child’s content.php
can simply replace the parent’s—but since include()
and require()
pull in files in a “non-WordPress” way, the child theme must instead replace every theme file that uses these template parts, creating huge unnecessary bulk in the child theme.
So when your “parent theme” has used get_template_part
take advantage. Just write the template part you need to override, and nothing more. The feature of
get_template_part
will help you. And, if you write your own theme, you should always use get_template_part()
where possible. It’ll make everyone happier.
Image credit: Mr.Thomas
wpshout.com
Хук get_template_part_{$slug}
Хук запускается в самом начале функции и позволяет выполнить какой-либо код в зависимости от значений переменных $slug
и $name
.
misha.blog
The hm_get_template_part
function by humanmade is extremely good at this and I use it all the time.
You call
hm_get_template_part( 'template_path', [ 'option' => 'value' ] );
and then inside your template, you use
$template_args['option'];
to return the value. It does caching and everything, though you can take that out if you like.
You can even return the rendered template as a string by passing 'return' => true
into the key/value array.
/** * Like get_template_part() put lets you pass args to the template file * Args are available in the tempalte as $template_args array * @param string filepart * @param mixed wp_args style argument list */ function hm_get_template_part( $file, $template_args = array(), $cache_args = array() ) { $template_args = wp_parse_args( $template_args ); $cache_args = wp_parse_args( $cache_args ); if ( $cache_args ) { foreach ( $template_args as $key => $value ) { if ( is_scalar( $value ) || is_array( $value ) ) { $cache_args[$key] = $value; } else if ( is_object( $value ) && method_exists( $value, 'get_id' ) ) { $cache_args[$key] = call_user_method( 'get_id', $value ); } } if ( ( $cache = wp_cache_get( $file, serialize( $cache_args ) ) ) !== false ) { if ( ! empty( $template_args['return'] ) ) return $cache; echo $cache; return; } } $file_handle = $file; do_action( 'start_operation', 'hm_template_part::' . $file_handle ); if ( file_exists( get_stylesheet_directory() . '/' . $file . '.php' ) ) $file = get_stylesheet_directory() . '/' . $file . '.php'; elseif ( file_exists( get_template_directory() . '/' . $file . '.php' ) ) $file = get_template_directory() . '/' . $file . '.php'; ob_start(); $return = require( $file ); $data = ob_get_clean(); do_action( 'end_operation', 'hm_template_part::' . $file_handle ); if ( $cache_args ) { wp_cache_set( $file, $data, serialize( $cache_args ), 3600 ); } if ( ! empty( $template_args['return'] ) ) if ( $return === false ) return false; else return $data; echo $data; }
wordpress.stackexchange.com
Структура шаблонов woocommerce
Я использую вот такую иерархию шаблонов woocommerce (уже немного отличающуюся от той которую использовал ранее)
<?php if ( is_product() ) : ?> Шаблон товара <?php elseif ( is_shop() ) : ?> <?php if ( is_search() ) : ?> Шаблон поиска <?php else: ?> Шаблон каталога товаров (витрина) <?php endif; ?> <?php else: ?> Шаблон категории товара <?php endif; ?>
Там где выводиться шаблон категории товара прописываем условия вывода.
<?php $product_cat = get_queried_object(); if($product_cat->slug == 'elektronika'): ?> Здесь будет верстка лэндинга! <?php get_template_part( 'woocommerce/taxonomy-product_cat-elektronika' ); ?> <?php else: ?> <h1 id="title"><?php printf( __( '%s', 'twentythirteen' ), single_cat_title( '', false ) ); ?></h1> <div class="box"> <?php get_sidebar(); ?> <div class="block-9" id="content"> <?php the_widget( 'WC_Widget_Layered_Nav_Filters' ); ?> <?php get_template_part( 'woocommerce/archive-product' ); //woocommerce_content(); ?> </div> </div> <?php endif; ?>
Можно не прописывать конструкцию
$product_cat = get_queried_object(); if($product_cat->slug == 'elektronika'):
А вместо нее использовать простое условие
if ( is_product_category( 'elektronika' ) ) :
Для прописанной категорий товара (в данном примере — Электроника) будет выводиться другой шаблон. Данный способ неудобен тем, что необходимо вручную прописывать условия. А если у нас будет много категорий с подкатегориями? В этом случае целесообразно задать таксономии новый параметр Шаблон в глобальную переменную term (по аналогии как это делает плагин taxonomy term image master).
Вывод разных шаблонов товаров в категории
Еще один уровень кастомизации категории WC это разные варианты вывода самих товаров. В этом случае мы должны по определенному запросу разделять визуализацию товаров. Если в простом варианте, то для определенных категорий выводить товары без цены. Если делать более продвинутый вариант — товары могут выводить вовсе по разному.
Если в назначении шаблона woocommerce использовать универсальную функцию woocommerce_content(); то почему то игнорируется шаблон archive-product.php. А для разделения вывода товаров в категории нужен именно archive-product.php.
get_template_part( ‘woocommerce/content-single-product’ ); — вывод карточки товара
get_template_part( ‘woocommerce/archive-product’ ); — вывод категории товара
get_template_part( ‘product-cat-list’ ); — разработанный мной шаблон вывода каталога товаров
woocommerce_content(); — вывод результатов поиска по товарам
В файле archive-product.php (внутри цикла while) нам нужно добавить условия вывода товаров и создать соответствующий файл в папке woocommerce/content-laminat.php
<?php $product_cat = get_queried_object(); if($product_cat->term_id == 24): ?> <?php wc_get_template_part( 'content', 'laminat' ); ?> <?php else: ?> <?php wc_get_template_part( 'content', 'product' ); ?> <?php endif; ?>
Создаем атрибут Шаблон у категории
Ранее мы пришли к выводу, что было бы удобнее создать в категориях параметр — Шаблон, в зависимости от которого будут выводиться разные шаблоны категорий. Так вот, я переделал плагин taxonomy term image master, создав новый плагин wc-template-select:
if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'Taxonomy_Term_Template' ) ) : class Taxonomy_Term_Template { // array of slugs for the taxonomies we are targeting // api: use filter 'taxonomy-term-template-taxonomy' to override private $taxonomies = array( 'category' ); // defined during __construct() for i18n reasons // api: use filter 'taxonomy-term-template-labels' to override private $labels = array(); // @deprecated: option_name for pre-term-meta data storage // api: use filter 'taxonomy.
te function __wakeup(){} // prevent unserialization // Init the plugin and hook into WordPress private function __construct() { // default labels $this->labels = array( 'fieldTitle' => __( 'Шаблон' ), 'fieldDescription' => __( 'Выберите шаблон, для этого элемента' ), 'adminColumnTitle' => __( 'Шаблон' ), ); // allow overriding of the html text $this->labels = apply_filters( 'taxonomy-term-template-labels', $this->labels ); // allow overriding of the target taxonomies $this->taxonomies = apply_filters( 'taxonomy-term-template-taxonomy', $this->taxonomies ); if ( ! is_array( $this->taxonomies ) ) { $this->taxonomies = array( $this->taxonomies ); } // @deprecated: allow overriding of option_name // default option name keyed to the taxonomy $this->option_name = $this->taxonomies[0] . '_term_templates'; $this->option_name = apply_filters( 'taxonomy-term-template-option-name', $this->option_name ); .
st' => false, ) ); // добавьте наши данные, когда срок будет восстановлен add_filter( 'get_term', array( $this, 'get_term' ) ); add_filter( 'get_terms', array( $this, 'get_terms' ) ); add_filter( 'get_object_terms', array( $this, 'get_terms' ) ); // нужно только добавить большинство хуков в админке if ( is_admin() ) { foreach ( $this->taxonomies as $taxonomy ) { // добавить поле Шаблон в формы таксономии add_action( $taxonomy . '_add_form_fields', array( $this, 'taxonomy_add_form' ) ); add_action( $taxonomy . '_edit_form_fields', array( $this, 'taxonomy_edit_form' ) ); // hook into term administration actions add_action( 'create_' . $taxonomy, array( $this, 'taxonomy_term_form_save' ) ); add_action( 'edit_' . $taxonomy, array( $this, 'taxonomy_term_form_save' ) ); // custom admin taxonomy term list columns add_filter( 'manage_edit-' . $taxonomy . '_columns', array( $this, 'taxonomy_term_column_template' ) ); add_filter( 'manage_' .
axonomy . '_custom_column', array( $this, 'taxonomy_term_column_template_content' ), 10, 3 ); } } } // Добавить новый столбец, который показывают выбранный шаблон. // @param $columns // @return mixed function taxonomy_term_column_template( $columns ){ $columns['term_template'] = $this->labels['adminColumnTitle']; return $columns; } // Показывать выбранное изображение термина во вновь созданном столбце администратора // @param $content // @param $column_name // @param $term_id // @return mixed function taxonomy_term_column_template_content( $content, $column_name, $term_id ){ if ( 'term_template' == $column_name ){ $term = get_term( $term_id ); if ( $term->term_template ) { $content = get_term_meta( $term_id, $this->term_meta_key, true ); } } return $content; } // Добавьте данные изображения к любому соответствующему вызову get_term (). Двойная функция как вспомогательная функция для этого -> get_terms (). // @param $_term // @return object function get_term( $_term ) { // только модифицируйте термин, когда имеете дело с нашими таксономиями if ( is_object( $_term ) && in_array( $_term->taxonomy, $this->taxonomies ) ) { // default to null if not found $template_id = get_term_meta( $_term->term_id, $this->term_meta_key, true ); $_term->term_template = !empty( $template_id ) ? $template_id : null; } return $_term; } // Добавьте term_template данные в объекты, когда вызывается get_terms () или wp_get_object_terms (). // @param $terms // @return array function get_terms( $terms ) { foreach( $terms as $i => $term ){ if ( is_object( $term ) && !empty( $term->taxonomy ) ) { $terms[ $i ] = $this->get_term( $term ); } } return $terms; } // HTML формы для термина таксономии // @param int $image_ID the image ID // @return string the html output for the image form function taxonomy_term_template_field($term) { wp_nonce_field( 'taxonomy-term-template-form-save', 'taxonomy-term-template-save-form-nonce' ); $params = array( 'table' => 'Таблица', 'landing' => 'Лэндинг', ); ?> <select id="taxonomy-term-template-id" name="taxonomy_term_template"> <option value="">По умолчанию</option>'; <?php foreach( $params as $val => $name ): ?> <option value="<?php echo $val; ?>" <?php echo selected( $term, $val, 0 ); ?>><?php echo $name; ?></option>'; <?php endforeach; ?> </select> <p class="description"><?php echo $this->labels['fieldDescription']; ?></p> <?php } // Добавить поле при создании нового термина таксономии function taxonomy_add_form($term){ ?> <div class="form-field term-image-wrap"> <label><?php echo $this->labels['fieldTitle']; ?></label> <?php $this->taxonomy_term_template_field($term); ?> </div> <?php } // Добавить поле при редактировании терминов таксономии // @param $term | object | the term object function taxonomy_edit_form( $term ){ // ensure we have our term_template data if ( !isset( $term->term_template ) ){ $term = $this->get_term( $term, $term->taxonomy ); } ?> <tr class="form-field"> <th scope="row" valign="top"><label><?php echo $this->labels['fieldTitle']; ?></label></th> <td class="taxonomy-term-template-row"> <?php $this->taxonomy_term_template_field( $term->term_template ); ?> </td> </tr> <?php } // Функция сохраняющая мета термина таксономии // @param $term_id function taxonomy_term_form_save( $term_id ) { // наши требования к сохранению: if ( // nonce был представлен и проверен isset( $_POST['taxonomy-term-template-save-form-nonce'] ) && wp_verify_nonce( $_POST['taxonomy-term-template-save-form-nonce'], 'taxonomy-term-template-form-save' ) && // данные о таксономии и данные taxonomy_term_template isset( $_POST['taxonomy'] ) && isset( $_POST['taxonomy_term_template'] ) && // представленная таксономия является одной из таксономий, с которыми мы имеем дело in_array( $_POST['taxonomy'], $this->taxonomies ) ) { // получить term_meta и назначить ему old_template $old_template = get_term_meta( $term_id, $this->term_meta_key, true ); // sanitize the data and save it as the new_template $new_template = $_POST['taxonomy_term_template']; // if an image was removed, delete the meta data if ( $old_template && '' === $new_template ) { delete_term_meta( $term_id, $this->term_meta_key ); } // if the new image is not the same as the old update the term_meta else if ( $old_template !== $new_template ) { update_term_meta( $term_id, $this->term_meta_key, $new_template ); } } } } endif; // Инициализируйте плагин, вызывая его экземпляр в WordPress action 'init' function taxonomy_term_template_init() { Taxonomy_Term_Template::instance(); } add_action( 'init', 'taxonomy_term_template_init' ); // Использовать для различных таксономий function the_term_template_taxonomy( $taxonomy ) { return array( 'product_cat', 'product_tag', 'category', 'brend' ); } add_filter( 'taxonomy-term-template-taxonomy', 'the_term_template_taxonomy' );
Одной из основных «фишек» плагина является то, что параметр term_template доступен из переменной WP_Term Object:
$product_cat = get_queried_object(); print_r($product_cat); Результат: WP_Term Object ( [term_id] => 107 [name] => Электроника [slug] => elektronika [term_group] => 0 [term_taxonomy_id] => 107 [taxonomy] => product_cat [description] => [parent] => 0 [count] => 1 [filter] => raw [term_template] => landing )
Далее прописываем условия по выводу шаблонов
<?php $product_cat = get_queried_object(); if ( $product_cat->term_template == 'landing' ) : ?> Шаблон лэндинга <?php elseif ($product_cat->term_template == 'table'): ?> Шаблон таблицы <?php else: ?> Шаблон по умолчанию <?php endif; ?>
Было бы здорово доработать проверку наличия шаблона у родительской категории, при отсутствии шаблона у текущей категории, но это уже излишне. По крайней мере назначить шаблон подкатегориям, причем сделать это можно при их создании, легче чем прописывать сами категории в условиях вывода.
Тэги: woocommerce
opttour.ru
Including files in a PHP environment can be tricky for new developers. There are no less than four ways to include a file: include, include_once, require, and require_once. Moreso, there’s very subtle differences in the reasons behind using each one. Throw in WordPress (which has its own specific flavor of include tag – get_template_part) and it can be downright confusing. Using the wrong one, especially in plugin development, can mean the difference between a working plugin and a fatal error.
Let’s break down the various tags and shed some light on their usage.
PHP ‘include’ and ‘include_once’
The include tags are fairly straightforward. From the PHP Manual:
<?php include(); ?> – The include statement includes and evaluates the specified file.
Simple enough. If you need to call in an external file, using include will bring all of the code into the script you’re running, at the exact spot you’ve placed the tag. This also means that the file gets access to all of the functions and variables you’ve previously written. It serves the same function as taking the file, copying its contents, and placing it in the same spot as the tag.
Include_once is very similar, but with one very important difference:
<?php include_once(); ?> – The include_once statement includes and evaluates the specified file during the execution of the script. This is a behavior similar to the include statement, with the only difference being that if the code from a file has already been included, it will not be included again. As the name suggests, it will be included just once.
Include_once is useful when you worry about variable reassignment or “double-calling” existing functions. Use it, and worry not about duplicate scripts being called.
PHP ‘require’ and ‘require_once’
The require tags are actually very similar as well. The key difference lies in the effect of calling a file that’s missing. From the manual:
<?php require(); ?> – require is identical to include except upon failure it will also produce a fatal
E_COMPILE_ERROR
level error. In other words, it will halt the script whereasinclude only emits a warning (E_WARNING
) which allows the script to continue.<?php require_once(); ?> – The require_once statement is identical to require except PHP will check if the file has already been included, and if so, not include (require) it again.
It’s amazing how easy it is to break these commands down, and yet how subtle the differences are. If you require a file, and that file doesn’t exist, it’ll throw an error message and will halt the script where it stands. Include, on the other hand, will simply throw a warning message, allowing the script to continue running.
PHP ‘get_template_part’
This is WordPress’ built in command to include files that are located in the theme’s directory. But it goes beyond that. Let’s look at a sample tag:
<?php get_template_part( 'loop', 'single' ); ?>
This is a fairly standard usage. Get_template_part works well with WordPress because it’s a degrading include – it looks for the more specific template first, before (upon failure to locate) moving to a more general template.
In this case, it would look for the files in this order:
-
wp-content/themes/childtheme/loop-single.php
-
wp-content/themes/parenttheme/loop-single.php
-
wp-content/themes/childtheme/loop.php
-
wp-content/themes/parenttheme/loop.php
It starts with the file in a child theme folder, then in the parent theme, and finally checking for a more generic template (child theme first).
www.mitchcanter.com
Recently, we’ve received several support requests regarding the get_template_part()
function from design firms that are working on child themes of our Nimbus WordPress Themes.
There seems to be some confusion about how this functions works and why we’ve chosen to implement it in our themes, so this post will look at what this important function offers and how it simplifies our themes.
About the get_template_part Function
Those of you who have delved into WordPress theme development or child theming likely understand that each theme is comprised of a set of minimum core templates – a stylesheet called style.css and an index.php file that organizes the display of content. In addition to these minimums, the WordPress application checks for higher level templates that fulfill a specific display role. An example of this would be an archive.php file that would organize the display of content on any archive page like a category feed.
Some parts of a website tend to be universal, so WordPress offers a handful of special “include” tags like get_header()
, get_footer()
, and get_sidebar()
. But what about for non-universal template sections that will be used multiple times or will be conditionally called upon depending on the business logic of the theme? For this we have the get_template_part()
function.
The get_template_part()
function acts like a PHP include()
or require()
, but with a few extra bells and whistles. You can actually follow the function paths backwards in core (see below) to the load_template()
function where you find the require()
and require_once()
functions being used.
/wp-includes/general-template.php
function get_template_part( $slug, $name = null ) { do_action( "get_template_part_{$slug}", $slug, $name ); $templates = array(); $name = (string) $name; if ( '' !== $name ) $templates[] = "{$slug}-{$name}.php"; $templates[] = "{$slug}.php"; locate_template($templates, true, false); }
/wp-includes/template.php
function locate_template($template_names, $load = false, $require_once = true ) { $located = ''; foreach ( (array) $template_names as $template_name ) { if ( !$template_name ) continue; if ( file_exists(STYLESHEETPATH . '/' . $template_name)) { $located = STYLESHEETPATH . '/' . $template_name; break; } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) { $located = TEMPLATEPATH . '/' . $template_name; break; } } if ( $load && '' != $located ) load_template( $located, $require_once ); return $located; }
/wp-includes/template.php
function load_template( $_template_file, $require_once = true ) { global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID; if ( is_array( $wp_query->query_vars ) ) extract( $wp_query->query_vars, EXTR_SKIP ); if ( $require_once ) require_once( $_template_file ); else require( $_template_file ); }
In addition to harnessing PHP require()
, get_template_part()
also provides a framework for template naming that follows the conventions used in other core WordPress include tags like get_header()
, get_sidebar()
, etc. This framework allows for the use of both a $slug
variable and a $name
variable such that you might have a $slug
with many alternate $name
versions or with none at all.
get_template_part( $slug ); get_template_part( $slug, $name_1 ); get_template_part( $slug, $name_2 )
Get_template_part also degrades sanely. If you request the partial: get_template_part( 'slug', 'name' );
and the file slug-name.php does not exist, the application will search for slug.php. If that also is not available, it will respond with no result, but it will not spin off an error the way require()
would.
Finally, get_template_part()
knows to look for child themes. This means you can override a parent theme partial by simply including a modified copy in the child theme.
How We Use It At Nimbus Themes
There are four ways that we use template partials at Nimbus Themes:
- Breaking out snippets of code or markup that will be used repeatedly.
- Removing clutter from higher level templates.
- Providing views that can be used conditionally.
- Better child theming.
Breaking out snippets of code or markup that will be used repeatedly.
When I first began coding themes for the Nimbus Themes collection, I had a tendency to bloat the template structure unnecessarily. I might create both a tag.php and a category.php when both could be handled by archive.php. A side effect of this was including elements like pagination on multiple templates. When a bug would come to my attention that affected this element, I would need to track it down on all the applicable templates. This became increasingly challenging as the complexity of the themes increased.
By breaking these elements into template partials and including them via the get_template_part()
function, the need to track and update in multiple locations was dispelled. Editing the partial would now fix the bug in all the higher level templates where the partial was in use.
Removing clutter from higher level templates.
Template partials are a great way to keep your top level templates clean and easy to read. An example of this is the index.php file in our Soliloquy Theme. Rather than create any secondary templates like archives.php, page.php, or search.php, I let everything default back to the index.php template which included the header, footer, and a loop.php partial.
get_header(); get_template_part( 'parts/loop'); get_footer();
This keeps the main template directory clean and pushes everything to the loop.php partial, where we sort through and organize the display.
Providing views that can be used conditionally.
Continuing with the example from the last section, we can look at the loop.php file in the Soliloquy theme, where we sort out which display layout to use depending on the class of content. Again, this is a perfect application for partials.
if (is_single()) { get_template_part( 'parts/content', 'single'); } else if (is_page()) { get_template_part( 'parts/content', 'page'); } else { get_template_part( 'parts/content', 'blog'); }
Note that this is a simple version, but you could target a variety of conditions, like whether or not a post has a featured image attachment or depending on the age of the content.
Better child theming.
While I’m including this topic last, it is by no means a minor concern. An issue we ran into with customers repeatedly was their creating a child theme that modified a higher level template which was subsequently modified in a theme update. Unfortunately, this would mean that the effects of the update would not be reflected on their theme even if they had only made a small edit to one element in a template that included many elements.
By using the get_template_part
function to include all the elements individually, our customers are able to modify one element at a time without having to worry about losing out on the benefits of regular theme updates.
Conclusion
Overall, the get_template_part
function offers a way to better organize themes and create better compatibility with core features and child themes.
I don’t imagine that I’ve found the perfect approach to using template partials, but I’ve found a system that works well for my team and clients. I’d also love to hear from other developers about how you use partials.
In closing, I hope this post provides some clarity to our customers about partials and what value they offer in our themes.
www.nimbusthemes.com
Всем привет! Сегодня на seo-mayak.com я познакомлю Вас с функцией get_template_part().
С выходом WordPress версии 3.0, структура шаблонов претерпела существенные изменения.
Если до этого шаблоны в основном состояли из стандартного набора файлов, таких как index.php, header.php, single.php, footer.php, archive.php, functions.php, sidebar.php, category.php, page.php, comments.php и style.css, то современные темы пестрят разными, не знакомыми названиями.
Что же изменилось? Просто у разработчиков появилась возможность подключать к основным файлам шаблона, дополнительные файлы, тем самым разбивая функционал, как бы, на отдельные секции.
Для чего это нужно? Делается это для сокращения повторений кода в основных файлах, что конечно облегчает верстку шаблонов, но зачастую вводит в тупик начинающих веб-мастеров.
В львиной доле статей, на тему расширения функционала сайтов на WordPress, описаны приемы, которые не вписываются в современную структуру шаблонов и образовался некий информационный вакуум, который я и собираюсь заполнить.
Надеюсь новичкам, после прочтении данной статьи, будет намного проще ориентироваться в шаблоне и изменять или дополнять его функционал. Поехали!
Функция get_template_part()
В качестве примера, возьмем тему twentyten, которая входит в стандартную сборку WordPress и доступна всем. Давайте посмотрим как устроен файл index.php. Если убрать все комментарии к коду, то содержимое файла будет следующим:
<?php get_header(); ?> <div id="container"> <div id="content" role="main"> <?php get_template_part( 'loop', 'index' );?> </div> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
Как не странно, в файле находится всего несколько строк кода. Вопрос, куда подевался цикл WordPress, постраничная навигация и т.д?
Вместо всего этого в коде прописана всего одна строчка:
<?php get_template_part( 'loop', 'index' );?>
А теперь откроем файл single.php и посмотрим что прописано там, естественно убрав комментарии к коду:
<?php get_header(); ?> <div id="container"> <div id="content" role="main"> <?php get_template_part( 'loop', 'single' );?> </div> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
Как видно код практически не изменился, за исключением одного слова в уже знакомой нам строчке:
<?php get_template_part( 'loop', 'single' );?>
Почему так устроены файлы и какую роль в них играет функция get_template_part()?
Название get_template_part можно перевести так: — «Присоединить часть шаблона». Т.е, существует файл, который является частью шаблона и функция get_template_part() его присоединяет.
Но как определить, какой файл присоединяется? Для этого надо разобраться с параметрами функции.
Параметры функции get_template_part()
Функция get_template_part() может принимать один или два параметра. На первом примере, приведенным мной выше, функция приняла два параметра:
( 'loop', 'index' )
Это ничто иное, как название файлов, расположенных в той же директории. Смотрим, действительно в шаблоне темы twentyten есть файл loop.php, в котором и находятся «потерянный» цикл WordPress. Также в шаблоне есть файл index.php.
Теперь давайте проведем несколько экспериментов (для экспериментов советую использовать Денвер).
Эксперимент №1. Уберем второй параметр из функции, т.е. функция примет такой вид:
<?php get_template_part( 'loop' );?>
Что произойдет? Удивительно, но главная страница загрузилась без ошибок и шаблон работает исправно.
Эксперимент №2. Уберем первый параметр, но оставим второй:
<?php get_template_part( 'index' );?>
Обновляем страницу. Опа! Фатальная ошибка, но шаблон при этом все равно загружается, правда уже без контента.
Эксперимент №3. А теперь попробуем поменять параметры местами:
<?php get_template_part( 'index', 'loop' );?>
Опять фатальная ошибка, все точно также, как при эксперименте №2. Почему так происходит?
Дело в том что первый параметр имеет приоритет, т.е. в данном случаи функция get_template_part() в первую очередь ищет файл loop.php, а если такой не будет обнаружен, то в качестве запасного варианта будет задействован файл index.php, для того, чтобы загрузился хотя бы шаблон.
Теперь посмотрим на файл single.php. Здесь функция get_template_part(), имеет следующие параметры:
( 'loop', 'single' )
Судя по проведенным ранее экспериментам, приоритетом присоединения должен обладать файл loop.php, так как он прописан в качестве первого параметра, но не тут то было.
В шаблоне есть еще один файл, который называется loop-single.php и именно он будет иметь более высокий приоритет, так как сочетает в своем названии оба параметра, прописанные через дефис. Такие дела! Но и это еще не все.
Если допустить, что у темы twentyten есть дочерняя тема, например twentyten two и в корне этой темы также существует файл loop-single.php, то функция get_template_part() присвоит вышеупомянутому файл, расположенному в дочерней теме, наивысший приоритет.
Если Вы не знаете, что такое дочерняя тема, для чего она нужна и как ее можно создать, то очень советую подписаться на обновления блога.
Теперь, когда мы знаем, как работает функция get_template_part(), то без труда сможем выявить любые прикрепленные файлы, даже если шаблон разделен на множество секций.
До встречи!
С уважением, Виталий Кириллов
seo-mayak.com
First Remark the false, false – they MUST be false otherwise the locate_template will jump to include the template itself, and also other empty results will occur.
I can see some confusing like “sharing variable between templates”.
Maybe I would add that:
The scope or the relationship is of importance between set and available get.
To make it easy to understand:
Only declared variables in the same scope, normally declared just before get_template_part… or locate_template.. or load_template… will automatic be accessible in the “next” scope, eg only directly inside the called template file.
The example in this post works fine with that, cause we are not in a next scope.
So, Your variable will get lost if that template call another template. And, It will not exists within a custom template function/ hook like my_filter_the_title().
This can be done by remain within the core methods, not use include “yourself” directly.
At the end, all built in WordPress methods are just wrappers for the final “load_template” that includes (requires) the file from the server. Before that function, “locate_template” is just a checker that & where the intended file exists, and first in the chain, get_template_part “just” starts building the filename a more easy way than PHP way. (very hypo speaking here)
So: include( locate_template( ‘content.php’, false, false ) ) is just a bypass to use the PHP native way to include more code “at the same spot” you are for the moment. And naturally, all your variables are there.
BUT, WordPress built in load_template() has another action before it requires the template-file from the server. It extracts arguments to the following scope. Therefore, Bypassing load_template() removes all arguments that might be needed in a shared template file. This is selldom a final problem, INSTEAD it is an opportunity for this task.
Another way of solving: The problem with get_template_part() variables
Step one is to choose your variables you need to pass before you template call like in this post example:
set_query_var(‘example’, $example);
while( have_posts() ): the_post(); get_template_part( ‘content’ );
$example is now avaible in the loaded template, thanks to native get_template_part() that uses load_template() at the end
Inside any filter in use by the current temaple, you can retrieve the variable(s) like:
add_filter(‘the_title’, ‘my_content_template_tilte’)
function my_content_template_tilte($title){
$example = get_query_var(‘example’);
return $title.’ added with ‘.$example;
}
You can actually pass the variable to the next template scope by set the custom query variable again, cause load_template will extract new arguments and your first set_query_var will be at no existance.
Just do it in the SAME scope where the load_template is in use. A smart way to do this “passing” is another thread.
mekshq.com