WordPress. Создание простой темы
18.05.2019
Теги: CMS • Web-разработка • WordPress • ШаблонСайта
Темы WordPress находятся в поддиректориях wp-content/themes
. Директория темы содержит файл стилей style.css
, около дюжины php-шаблонов и файл дополнительного функционала functions.php
. Файлы index.php
и style.css
являются обязательными. Файл стилей style.css
обязательно должен содержать информацию о теме в комментарии.
Давайте создадим простую тему для WordPress и рассмотрим назначение всех файлов. Кроме того, подключим фреймворк Bootstrap 3 — для упрощения верстки. Тема будет содержать только необходимый минимум, чтобы ничто не отвлекало от главного. В дальнейшем, после изучения всех шаблонов, можно использовать эту тему как каркас для создания новых тем.
Создаем директорию темы clean
и добавляем в нее файлы style.css
и index.php
:
/*
Theme Name: clean
Version: 1.0.0
Text Domain: clean
*/
<?php /** * Файл index.php. Максимально универсальный шаблон, используется для показа * любых страниц сайта, если не был найден более подходящий шаблон */ /* * Подключаем шапку сайта */ get_header(); ?> <p><?php _e('Не найден шаблон для показа этой страницы', 'clean'); ?></p> <?php /* * Подключаем подвал сайта */ get_footer();
Создаем поддиректорию assets
, копируем в нее все css и js файлы шаблона. Создаем файл functions.php
, который формально не является обязательным, но без которого тему не создать:
<?php add_action('after_setup_theme', 'current_theme_setup'); function current_theme_setup() { /* * Загружаем файл перевода темы в память */ load_theme_textdomain('clean', get_template_directory() . '/languages'); /* * Включаем поддержку форматов постов (это редко используется) */ add_theme_support( 'post-formats', [ 'audio', 'video', 'gallery', /* 'aside', 'link', 'image', 'quote', 'status', 'chat' */ ] ); /* * Добавляем поддержку автоматического добавления тега <title> */ add_theme_support('title-tag'); /* * Добавляем поддержку миниатюр для всех типов постов */ add_theme_support('post-thumbnails'); /* * Регистрируем расположение для двух меню — в шапке и в подвале */ register_nav_menus([ 'header_menu' => esc_html__('Меню в шапке', 'clean'), 'footer_menu' => esc_html__('Меню в подвале', 'clean') ]); /* * Добавляем возможность загрузки своего фона для <body> */ add_theme_support( 'custom-background', array( 'default-color' => 'FFFFFF', 'default-image' => '', ) ); /* * Добавляем возможность установки фона для шапки сайта. Изменять * можно не только фоновое изображение, но и цвет заголовка. */ add_theme_support( 'custom-header', [ 'default-color' => 'FFFFFF', 'default-text-color' => '000000', 'default-image' => '', 'width' => 3000, 'height' => 500, ] ); /* * Добавляем возможность загрузки своего логотипа */ add_theme_support( 'custom-logo', array( 'height' => 250, 'width' => 250, 'flex-width' => true, 'flex-height' => true, ) ); /* * Добавляем поддержку selective refresh (выборочное обновление) в * Theme Customizer для виджетов */ add_theme_support('customize-selective-refresh-widgets'); } /* * Регистрируем место для сайдбара в боковой колонке */ add_action( 'widgets_init', function () { register_sidebar( array( 'name' => esc_html__('Боковая колонка', 'clean'), 'id' => 'sidebar_right', 'description' => esc_html__( 'Перетащите сюда виджеты, чтобы добавить их в сайдбар', 'clean' ), 'before_widget' => '<section id="%1$s" class="widget %2$s">', 'after_widget' => '</section>', 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); } ); /* * Подключаем файлы стилей и скриптов */ add_action( 'wp_enqueue_scripts', function () { /* * Подключаем файлы стилей */ wp_enqueue_style( 'current-theme-bootstrap', // будет зарегистрирован под этим именем get_template_directory_uri() . '/assets/bs/css/bootstrap.min.css' ); wp_enqueue_style( 'current-theme-style', // будет зарегистрирован под этим именем get_template_directory_uri() . '/assets/css/style.css', // должен быть подключен после этих css-файлов [ 'current-theme-bootstrap' ] ); wp_enqueue_style( 'default-theme-style', // будет зарегистрирован под этим именем get_stylesheet_uri(), // должен быть подключен после этих css-файлов [ 'current-theme-bootstrap', 'current-theme-style' ] ); /* * Подключаем файлы скриптов */ wp_enqueue_script( 'current-theme-bootstrap', // будет зарегистрирован под этим именем get_template_directory_uri() . '/assets/bs/js/bootstrap.min.js', array('jquery'), // должен быть подключен после jquery null, // версии нет, поэтому null true // подключаем перед закрывающим тегом body ); wp_enqueue_script( 'current-theme-script', // будет зарегистрирован под этим именем get_template_directory_uri() . '/assets/js/script.js', array('jquery'), // должен быть подключен после jquery null, // версии нет, поэтому null true // подключаем перед закрывающим тегом body ); } ); /* * Задаем css-стили для элементов меню навигации, чтобы использовать * готовые стили Bootstrap 3 */ add_filter( 'nav_menu_css_class', function($classes, $item) { /* * Переменная $classes содержит * Array( * [1] => menu-item * [2] => menu-item-type-post_type * [3] => menu-item-object-page * [4] => menu-item-1911 * ) */ // удаляем все css-классы, которые устанавливает WP $classes = []; if ($item->current) { // добавляем класс active для текущей страницы $classes[1] = 'active'; } return $classes; }, 10, 2 ); /* * Функция для вывода постраничной навигации с использованием классов * Bootstrap 3 * * <nav aria-label="Постраничная навигация"> * <ul class="pagination"> * <li><a href="#">Предыдущая</a></li> * <li><a href="#">1</a></li> * <li class="active"><a href="#">2</a></li> * <li><a href="#">3</a></li> * <li class="disabled"><a href="#">…</a></li> * <li><a href="#">9</a></li> * <li><a href="#">Следующая</a></li> * </ul> * </nav> */ function echo_posts_pagination($echo = true) { $items = paginate_links(['type' => 'array']); if (empty($items)) { return null; } $links = []; foreach ($items as $item) { $url = $txt = $type = ''; if (preg_match('~href=("|\')([^"\']+)\1>([^<]+)</a>~', $item, $match)) { $url = $match[2]; $txt = $match[3]; $type = 'link'; } if (preg_match('~page-numbers current("|\')>([^<]+)</span>~', $item, $match)) { $txt = $match[2]; $type = 'curr'; } if (preg_match('~page-numbers dots("|\')>([^<]+)</span>~', $item, $match)) { $txt = $match[2]; $type = 'dots'; } $links[] = ['type' => $type, 'url' => $url, 'txt' => $txt]; } if (empty($links)) { return null; } $html = '<nav aria-label="Постраничная навигация">' . "\n"; $html .= ' <ul class="pagination">' . "\n"; foreach ($links as $link) { if ($link['type'] == 'link') { $html .= ' <li>'; $html .= '<a href="'.$link['url'].'">'.$link['txt'].'</a>'; $html .= '</li>' . "\n"; } elseif ($link['type'] == 'curr') { $html .= ' <li class="active">'; $html .= '<span>'.$link['txt'].'</span>'; $html .= '</li>' . "\n"; } elseif ($link['type'] == 'dots') { $html .= ' <li class="disabled">'; $html .= '<span>'.$link['txt'].'</span>'; $html .= '</li>' . "\n"; } } $html .= ' </ul>' . "\n"; $html .= '</nav>' . "\n"; if ($echo) { echo $html; return null; } return $html; } /* * Подключаем настройщик темы (Theme Customiser) */ require get_template_directory() . '/customizer/customizer.php';
Остальные файлы темы:
<?php /** * Файл header.php. Шапка сайта, подключается на всех страницах сайта */ ?> <!doctype html> <html <?php language_attributes(); ?>> <head> <meta charset="<?php bloginfo('charset'); ?>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <?php wp_head(); ?> </head> <body <?php body_class(); ?>> <header> <?php /* * Фоновое изображение шапки сайта. Если пользователь не загрузил * изображение, то оно не будет показано */ $style = ''; if (has_custom_header()) { $style = ' style="background-image: url('.get_header_image().')"'; } ?> <div<?= $style; ?>> <div class="container"> <span id="blogname" style="color: #<?php header_textcolor(); ?>"> <?php bloginfo('name'); ?> </span> <span id="blogdescription" style="color: #<?php header_textcolor(); ?>"> <?php bloginfo('description'); ?> </span> </div> </div> <nav class="navbar navbar-inverse"> <div class="container"> <div class="navbar-header"> <a href="<?= home_url(); ?>" class="navbar-brand<?= is_front_page() ? ' active': ''; ?>"> <span class="glyphicon glyphicon-home"></span> </a> </div> <div class="collapse navbar-collapse" id="main-menu"> <?php wp_nav_menu([ 'theme_location' => 'header_menu', 'container' => false, 'menu_class' => 'nav navbar-nav', 'menu_id' => 'main-menu-ul', ]); ?> <div class="navbar-right"> <?php if ( ! is_user_logged_in()): ?> <a href="<?= wp_registration_url(); ?>" class="btn btn-default navbar-btn"> <?php _e('Регистрация', 'clean'); ?> </a> <?php endif; ?> <?php if ( ! is_user_logged_in()): ?> <a href="<?= wp_login_url(get_permalink()); ?>" class="btn btn-default navbar-btn"> <?php _e('Войти', 'clean'); ?> </a> <?php else: ?> <a href="<?= wp_logout_url(get_permalink()); ?>" class="btn btn-default navbar-btn"> <?php _e('Выйти', 'clean'); ?> </a> <?php endif; ?> </div> <?php get_search_form(); ?> </div> </div> </nav> </header>
<?php /** * Файл footer.php. Подвал сайта, подключается на всех страницах сайта */ ?> <footer> <div class="container"> <div class="row"> <div class="text-center"> <p>© All Rights Reserved.</p> </div> </div> </div> </footer> <?php wp_footer(); ?> </body> </html>
<?php /** * Файл sidebar.php. Сайдбар (боковая панель) */ ?> <?php if (is_active_sidebar('sidebar_right')): ?> <div id="sidebar_right" class="sidebar"> <?php dynamic_sidebar('sidebar_right'); ?> </div> <?php endif; ?>
<?php /** * Файл front-page.php. Шаблон для главной страницы сайта */ /* * Подключаем шапку сайта */ get_header(); /* * Здесь возможны две ситуации: на главной странице показываются последние * записи или на главной показывается статическая страница. */ ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php if (is_home()) { // показываются последние записи get_template_part('parts/list'); } else { // показывается статическая страница get_template_part('parts/page'); } ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл home.php. Шаблон для показа списка последних постов, используется, * когда на главной странице показывается статическая страница */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php get_template_part('parts/list'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл page.php. Шаблон для показа страницы (запись типа page) */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php get_template_part('parts/page'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл single.php. Шаблон для показа отдельной записи произвольного типа, * кроме страниц (тип записи page) */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <?php get_template_part('parts/single'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл archive.php. Шаблон для показа списка архивных записей */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <h1><?php the_archive_title(); ?></h1> <p><?php the_archive_description(); ?></p> <?php get_template_part('parts/list'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл search.php. Шаблон для показа результатов поиска по сайту */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main class="col-md-9"> <h1><?php esc_html_e('Поиск по сайту', 'clean'); ?></h1> <?php if (!empty(get_search_query())): ?> <h2> <?php esc_html_e('Результаты поиска для: ', 'clean'); echo get_search_query(); ?> </h2> <?php endif; ?> <?php get_template_part('parts/list'); ?> </main> <aside class="col-md-3"> <?php get_sidebar(); ?> </aside> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
<?php /** * Файл searchform.php. Шаблон формы поиска */ ?> <form method="get" action="<?= home_url('/'); ?>" id="searchform" class="navbar-form navbar-right" role="search"> <div class="form-group"> <input type="text" name="s" id="s" value="<?= get_search_query(); ?>" class="form-control" placeholder="Поиск по сайту"> </div> <button type="submit" class="btn btn-default">Искать</button> </form>
<?php /** * Файл comments.php. Шаблон для вывода комментариев */ ?> <div id="clean-comments"> <?php if (have_comments()): ?> <h2><?php esc_html_e('Комментарии', 'clean'); ?></h2> <?php the_comments_navigation(); ?> <ol class="comment-list"> <?php wp_list_comments([ 'style' => 'ol', 'short_ping' => true, ]); ?> </ol> <?php the_comments_navigation(); if (!comments_open()): ?> <p class="no-comments"> <?php esc_html_e( 'Комментарии закрыты', 'clean' ); ?> </p> <?php endif; endif; comment_form(); ?> </div>
<?php /** * Файл 404.php. Шаблон для страницы 404 Not Found */ /* * Подключаем шапку сайта */ get_header(); ?> <div id="content"> <div class="container"> <div class="row"> <main id="clean-notfound"> <h1><?php _e('Страница не найдена', 'clean'); ?></h1> <p> <?php _e( 'Запрошенная страница не найдена, попробуйте воспользоваться поиском.', 'clean' ); ?> </p> <?php // поиск по сайту the_widget('WP_Widget_Search'); // категории блога the_widget('WP_Widget_Categories'); // свежие записи the_widget( 'WP_Widget_Recent_Posts' ); // сттаницы сайта the_widget('WP_Widget_Pages'); // облако тегов the_widget('WP_Widget_Tag_Cloud'); ?> </main> </div> </div> </div> <?php /* * Подключаем подвал сайта */ get_footer();
Составные части шаблонов, размещаются в поддиректории parts
:
<?php /** * Файл parts/list.php. Список записей с постраничной навигацией */ ?> <?php if (have_posts()): ?> <ul class="media-list"> <?php while (have_posts()): ?> <?php the_post(); ?> <li class="media well"> <div class="media-left"> <?php $default = get_template_directory_uri().'/assets/img/default-background.jpg'; $thumbnail = get_the_post_thumbnail_url(null, 'thumbnail') ?: $default; ?> <img class="media-object" src="<?= $thumbnail; ?>" alt=""> </div> <div class="media-body"> <h4 class="media-heading"><?php the_title(); ?></h4> <p><?php the_excerpt(); ?></p> <p> <a href="<?php the_permalink(); ?>" class="btn btn-default"> <?php _e('Читать дальше', 'clean'); ?> </a> </p> </div> </li> <?php endwhile; ?> </ul> <?php echo_posts_pagination(); ?> <?php else: ?> <p><?php _e('Ничего не найдено', 'clean'); ?></p> <?php endif; ?>
<?php /** * Файл parts/page.php. Шаблон для страницы сайта (тип записи page) */ ?> <?php if (have_posts()): ?> <div id="clean-page"> <?php the_post(); ?> <h1><?php the_title(); ?></h1> <?php the_content(); ?> </div> <?php endif; ?>
<?php /** * Файл parts/single.php. Шаблон для показа отдельной записи произвольного типа, * кроме страниц (тип записи page) */ ?> <?php if (have_posts()): ?> <div id="clean-single"> <?php the_post(); ?> <h1><?php the_title(); ?></h1> <?php the_content(); ?> <ul class="pager"> <li class="previous"> <?php previous_post_link( '%link', __('Предыдущая', 'clean') ); ?> </li> <li class="next"> <?php next_post_link( '%link', __('Следующая', 'clean') ); ?> </li> </ul> </div> <?php comments_template(); ?> <?php endif; ?>
Настройки темы через Theme Customizer:
<?php /* * Файл customizer/customizer.php. Когда пользователь изменяет настройки темы в Theme * Customizer и наблюдает изменения в окне предварительного просмотра */ add_action( 'customize_register', function($wp_customize) { /* * Обновление окна предварительного просмотра настроек темы без перезагрузки */ $wp_customize->get_setting('blogname')->transport = 'postMessage'; $wp_customize->get_setting('blogdescription')->transport = 'postMessage'; $wp_customize->get_setting('header_textcolor')->transport = 'postMessage'; $wp_customize->selective_refresh->add_partial( 'blogname', array( 'selector' => '#blogname', 'render_callback' => function() { bloginfo('name'); } ) ); $wp_customize->selective_refresh->add_partial( 'blogdescription', array( 'selector' => '#blogdescription', 'render_callback' => function() { bloginfo('description'); } ) ); } ); /* * Подключаем js-файл, который будет обновлять без перезагрузки окно * предварительного просмотра сайта при изменении настроек темы */ add_action( 'customize_preview_init', function () { wp_enqueue_script( 'clean-customizer', get_template_directory_uri() . '/customizer/customizer.js', array('customize-preview'), null, true ); } );
/** * Файл customizer/customizer.js. Обновляет окно предварительного просмотра, * когда пользователь изменяет настройки сайта */ (function($) { // Изменяем цвет заголовка wp.customize('header_textcolor', function(value) { value.bind(function(to) { $('#blogname, #blogdescription').css('color', to); }); }); })(jQuery);
Дополнительно
Поиск: CMS • Web-разработка • WordPress • Шаблон сайта • Тема • Bootstrap