Создание темы wordpress

В статье Разработка сайта ecotoys.by я рассказывал как создать дочернюю тему wordpress. Наконец дошли руки и до родительской темы.
Темы для wordpress размещаются в каталоге [SITE_DIR]/wp-content/themes, для создания темы необходимо создать новую папку [THEME_NAME], т.е.
[SITE_DIR]/wp-content/themes/[THEME_NAME].
Для того, чтобы wordpress увидело нашу тему достататочно создать файл style.css с легендой типа

/*
Theme Name: ITPharma
Theme URI: https://itpharma.by
Author: Siarhei Dudko
Author URI: https://sergdudko.tk
Description: Тема для сайта itpharma.by
Version: 1.0
License: MIT
Text Domain: itpharma
*/

Содержимое легенды интуитивно понятно, обязательные поля это:

  • Theme Name — наименование темы
  • Text Domain — наименование папки с темой [THEME_NAME]

Остальные поля Author (гиперссылка на Author URI), Description, Version видно на рисунке:

далее в style.css сделаю отступ в 10px в контенте сайта:

#bodycontent{
	margin: 10px;
}

Чтобы сайт c установленной темой начал что-либо выводить, необходимо создать в папке [THEME_NAME] файл index.php,

<?php
/**
 * Основная тема для сайта itpharma.by
 *
 * @package ITPharma
 * @subpackage ITPharma
 * @since 1.0
 * @version 1.0
 * @author Siarhei Dudko
 */
?>

<?php get_header(); ?>

<div id="bodycontent">
	<?php
		echo apply_filters('the_content', get_post()->post_content);
	?>
</div>

<?php get_footer(); ?>

,где

  • apply_filters(‘the_content’, get_post()->post_content) — выведет html-код записи страницы
  • get_header() и get_footer() запросит [THEME_NAME]/header.php и [THEME_NAME]/footer.php. Чтобы страница отображалась нужно создать соответственно header.php и footer.php (пока оставим их пустыми).

Тему буду строить на основе Bootstrap v4. Для его работы создам папки [THEME_NAME]/js и [THEME_NAME]/css. В папку js положу скрипты jquery-3.4.0.min.js и bootstrap.min.js, в css файлы стилей bootstrap.min.css, bootstrap-grid.min.css, bootstrap-reboot.min.css
Подключить их к каждой странице можно двумя способами:

  • Вставив html-код в header.php. например, для подключения css:
    <link rel="stylesheet" href="<?php echo get_stylesheet_directory_uri().'/css/bootstrap.min.css' ?>" />

    ,где

    • get_stylesheet_directory_uri() — директория темы (ссылка)
  • Подключив через API wordpress в скрипте functions.php (я буду использовать этот путь), для этого создам скрипт [THEME_NAME]/functions.php и добавлю в него
    <?php
    function itpharma_wptuts_scripts_basic()  
    {  
    	wp_register_script( 'jquery', get_stylesheet_directory_uri() . '/js/jquery-3.4.0.min.js', '', '3.4.0' );  
        wp_enqueue_script( 'jquery' );
    	
    	wp_register_script( 'bootstrapminjs', get_stylesheet_directory_uri() . '/js/bootstrap.min.js', '', '4.3.1' );  
        wp_enqueue_script( 'bootstrapminjs' );
    	
    	wp_register_style( 'bootstrapmincss', get_stylesheet_directory_uri() . '/css/bootstrap.min.css', '', '4.3.1' );  
        wp_enqueue_style( 'bootstrapmincss' );
    	
    	wp_register_style( 'bootstrap-gridmincss', get_stylesheet_directory_uri() . '/css/bootstrap-grid.min.css', '', '4.3.1' );  
        wp_enqueue_style( 'bootstrap-gridmincss' );
    	
    	wp_register_style( 'bootstrap-rebootmincss', get_stylesheet_directory_uri() . '/css/bootstrap-reboot.min.css', '', '4.3.1' );  
        wp_enqueue_style( 'bootstrap-rebootmincss' );
    }  
    add_action( 'wp_enqueue_scripts', 'itpharma_wptuts_scripts_basic' );

    Следует обратить внимание, что после <?php не должно быть закрывающего тега ?>.
    Функция wp_register_script регистрирует скрипт, wp_enqueue_script подключает его в header (для этого в странице должен быть вызвана функция wp_head()). События должны быть переданы в метод wp_enqueue_scripts.

     

В этом же скрипте отключу ненужный функционал в wordpress (мусор на странице):

function itpharma_delete_junk_from_header() {
    remove_action( 'wp_head', 'feed_links', 2 ); // Удаляет ссылки RSS-лент записи и комментариев
    remove_action( 'wp_head', 'feed_links_extra', 3 ); // Удаляет ссылки RSS-лент категорий и архивов
    
    remove_action( 'wp_head', 'rsd_link' ); // Удаляет RSD ссылку для удаленной публикации
    remove_action( 'wp_head', 'wlwmanifest_link' ); // Удаляет ссылку Windows для Live Writer
    
    remove_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0); // Удаляет короткую ссылку
    remove_action( 'wp_head', 'wp_generator' ); // Удаляет информацию о версии WordPress
    remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 ); // Удаляет ссылки на предыдущую и следующую статьи
    
    // отключение WordPress REST API
    remove_action( 'wp_head', 'rest_output_link_wp_head' ); 
    remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
    remove_action( 'template_redirect', 'rest_output_link_header', 11, 0 );
}
add_filter( 'after_setup_theme', 'itpharma_delete_junk_from_header' );

Функция remove_action удаляет события, все remove_action должны быть переданы в метод after_setup_theme.

А также добавляю поддержку темой логотипа, фона и меню.

function itpharma_theme_support() {
	//добавляю кастомный лого
	add_theme_support( 'custom-logo', [
		'height'      => 30,
		'width'       => 30,
		'flex-width'  => false,
		'flex-height' => false,
		'header-text' => 'ITPharma',
	] );
	//добавляю кастомный фон
	add_theme_support( 'custom-background' );
	$defaults = array(
		'default-color'          => '',
		'default-image'          => '',
		'default-repeat'         => 'repeat', // повторять
		'default-position-x'     => 'left', // выровнять по левому краю
		'default-attachment'     => 'fixed', // фон прокручивается со страницей
		'wp-head-callback'       => '_custom_background_cb',
		'admin-head-callback'    => '',
		'admin-preview-callback' => ''
	);
	add_theme_support( 'custom-background', $defaults );
	//добавляю меню
	register_nav_menu( 'primary', 'Основное меню' );
}
add_filter( 'after_setup_theme', 'itpharma_theme_support' );

Функция add_theme_support добавляет поддержку темой функционала, а register_nav_menu регистрирует меню по умолчанию. Функции должны быть переданы в метод after_setup_theme.

Теперь через настройку темы у нас доступны настройка фона из меню Настроить->Цвета->Цвет фона:

Либо как фоновое изображение через Настроить->Фоновое изображение:

А также выбор логотипа через Настроить->Свойства сайта->Логотип

И настройка меню, через Настроить->Меню->Создать меню (установить флаг Основное меню)

В этом же скрипте functions.php добавлю кастомизатор темы:

function itpharma_customize_register($wp_customize) {
	//имя секции настроек
	$wp_customize->add_section( 'itpharma_customizer' , array(
		'title'      => __('Настройка темы','mytheme'),
		'priority'   => 30,
	));
	//стиль шапки
	$wp_customize->add_setting( 'itpharma_header_style' , array(
		'default' => 'dark',
	));
	//контроллер стиля шапки
	$wp_customize->add_control( new WP_Customize_Control(
		$wp_customize,
		'itpharma_header_style_type', 
		array(
			'label'    => __( 'Стиль шапки', 'itpharma' ),
			'section'  => 'itpharma_customizer',
			'settings' => 'itpharma_header_style',
			'type'     => 'radio',
			'choices'  => array(
				'dark'  => 'Темный фон',
				'light' => 'Светлый фон',
			),
		)
	));
	//цвет шапки
	$wp_customize->add_setting( 'itpharma_header_background' , array(
		'default' => '#007bff',
		'sanitize_callback' => 'sanitize_hex_color',
	));
	//контроллер цвета шапки
	$wp_customize->add_control( new WP_Customize_Color_Control( 
		$wp_customize, 
		'itpharma_header_background_color', 
		array(
			'label'      => __( 'Цвет шапки', 'itpharma' ),
			'section'    => 'itpharma_customizer',
			'settings'   => 'itpharma_header_background',
				'priority'   => 1
		)
	));
	//код в шапке
	$wp_customize->add_setting( 'itpharma_header_code' , array(
		'default' => '',
	));
	//контроллер кода в шапке
	$wp_customize->add_control( new WP_Customize_Control(
		$wp_customize,
		'itpharma_header_code_text', 
		array(
			'label'    => __( 'HTML-код в шапке', 'itpharma' ),
			'section'  => 'itpharma_customizer',
			'settings' => 'itpharma_header_code',
			'type'     => 'textarea',
		)
	));
	//код в подвале
	$wp_customize->add_setting( 'itpharma_footer_code' , array(
		'default' => '',
	));
	//контроллер кода в подвале
	$wp_customize->add_control( new WP_Customize_Control(
		$wp_customize,
		'itpharma_footer_code_text', 
		array(
			'label'    => __( 'HTML-код в подвале (google analitycs, yandex metrics и т.п.)', 'itpharma' ),
			'section'  => 'itpharma_customizer',
			'settings' => 'itpharma_footer_code',
			'type'     => 'textarea',
		)
	));
}
add_action( 'customize_register', 'itpharma_customize_register' );

Метод $wp_customize->add_section добавляет секцию в настройки:

Метод $wp_customize->add_setting добавляет пункт настроек. В данном случае я буду использовать bootstrap navigation, для изменения цвета фона меню зарегистрирую соответствующую настройку:

$wp_customize->add_setting( 'itpharma_header_background' , array(
	'default' => '#007bff',
	'sanitize_callback' => 'sanitize_hex_color',
));

После регистрации настройки со значением по-умолчанию, необходимо добавить контроллер настройки методом $wp_customize->add_control, для случая цвет фона меню это

$wp_customize->add_control( new WP_Customize_Color_Control( 
	$wp_customize, 
	'itpharma_header_background_color', 
	array(
		'label'      => __( 'Цвет шапки', 'itpharma' ),
		'section'    => 'itpharma_customizer',
		'settings'   => 'itpharma_header_background',
			'priority'   => 1
	)
));

Аналогичным принципом зарегистрирую стиль фона меню (светлый текст или темный из стандартных классов bootstrap). А также добавлю два поля для ввода кода в header.php и footer.php. Данные методы должны быть переданы методу customize_register.

Теперь можно заняться скриптами header и footer. В footer.php вставлю:

<?php wp_footer() ?>
<?php 
	$headercode = get_theme_mod('itpharma_footer_code');
	if($headercode)
		echo $headercode;
?>
</body>
</html>

,где

  • wp_footer() — вызов стандартного footer wordpress.
  • get_theme_mod(‘itpharma_footer_code’) — html-код из Настроить->Настройка темы->HTML-код в подвале

В header.php добавлю код:

<!DOCTYPE html>
<html><head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
	<link rel="stylesheet" href="<?php echo get_stylesheet_uri() ?>" />
	<title><?php echo get_bloginfo("description") . ' - ' . get_page_by_path(get_page_uri())->post_title; ?></title>
	<?php wp_head() ?>
	<style type="text/css">
		body{ <?php 
			$backgroundimg = get_background_image();
			$backgroundcolor = get_background_color();
			if($backgroundcolor){
				echo 'background-color: #'.$backgroundcolor.';';
			}
			if($backgroundimg){
				echo 'background-image:url('.$backgroundimg.')';
			}
		?> }
	</style>
</head>
<body  <?php body_class() ?>>
<?php 
	$headercode = get_theme_mod('itpharma_header_code');
	if($headercode)
		echo $headercode;
?>
<nav class="navbar navbar-expand-lg <?php 
	$headerstyle = get_theme_mod('itpharma_header_style');
	switch($headerstyle){
		case 'dark':
			echo 'navbar-dark';
			break;
		case 'light':
			echo 'navbar-light';
			break;
		default:
			echo 'navbar-light';
			break;
	}
?>" style="z-index: 1000;<?php 
	$headercolor = get_theme_mod('itpharma_header_background');
	if($headercolor){ echo 'background-color: '.$headercolor.';'; } 
?>">
	<a class="navbar-brand" href="#"><?php 
		$logotext = get_bloginfo("name");
		if(has_custom_logo()){
			$imglink = wp_get_attachment_image_src( get_theme_mod( 'custom_logo' ), 'full' );
			echo '<img src="'.$imglink[0].'" width="30" height="30" alt="">';
		}
		if($logotext){
			echo $logotext;
		} else {
			echo 'Логотип';
		}
	?></a>
	<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
		<span class="navbar-toggler-icon"></span>
    </button>
	<div class="collapse navbar-collapse" id="navbarText">
		<ul class="navbar-nav mr-auto">
			<?php
				$menu = wp_get_nav_menu_items(get_nav_menu_locations()['primary']);
				foreach( $menu as $page ){ 
					if(get_permalink() == ($page->url)){
						echo '<li class="nav-item active"><a class="nav-link" href="'.$page->url.'">'.esc_html($page->title).'<span class="sr-only">(current)</span></a></li>';
					} else {
						echo '<li class="nav-item"><a class="nav-link" href="'.$page->url.'">'.esc_html($page->title).'</a></li>';
					}
				}
			?>
		</ul>
	</div>
</nav>

,где

  • get_stylesheet_uri() — ссылка на style.css темы
  • get_bloginfo(«description») — краткое описание из Настроить->Свойства сайта->Краткое описание
  • get_page_by_path(get_page_uri())->post_title — наименование страницы
  • wp_head() — генерирует html-код заголовков wordpress, в том числе подключенный через api bootstrap
  • get_background_image() — ссылка на фоновое изображение (если присвоено), из Настроить->Фоновое изображение
  • get_background_color() — код цвета фона (если задан)
  • get_theme_mod(‘itpharma_header_code’) — html-код из поля Настроить->Настройка темы->HTML-код в шапке
  • get_theme_mod(‘itpharma_header_style’) — стиль темы (цвет шрифта) из Настроить->Настройка темы->Стиль шапки
  • get_theme_mod(‘itpharma_header_background’) — цвет фона шапки из Настроить->Настройка темы->Цвет шапки
  • get_bloginfo(«name») — Наименование сайта из Настроить->Свойства сайта->Название сайта
  • wp_get_attachment_image_src( get_theme_mod( ‘custom_logo’ ), ‘full’ ) — ссылка на изображение логотипа из Настроить->Свойства сайта->Логотип
  • wp_get_nav_menu_items(get_nav_menu_locations()[‘primary’]) — объект меню (далее [MENU]) из Настроить->Меню->Основное меню
  • get_permalink() — ссылка на текущую страницу
  • [MENU]->[..PAGE]->url — ссылка на страницу
  • [MENU]->[..PAGE]->title — название страницы

В принципе тема уже вполне рабочая. Для красоты отображения в списке тем, необходимо в каталог с темой ( [SITE_DIR]/wp-content/themes/[THEME_NAME]/ ) положить её скриншот: screenshot.png

В качестве последнего штриха создадам страницу ошибки (404), для этого в каталоге с темой создам скрипт 404.php:

<?php get_header(); ?>

<head>
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
	<style type="text/css">
	#bodycontent {
		width:100%;
		height:100%;
		overflow:hidden;
		margin:0px;
		padding:0px;
		font-family:'Open Sans',sans-serif;
		font-size:16px
	}
	#imgageline{
		width: 100%;
		text-align:right;
	}
	#imgageline img{
		max-width: 25%;
	}
	#error{
		padding-top: 50px;
		color: #0088e2;
	}
	</style>
</head>

<div id="bodycontent">
	<div id="imgageline">
		<img src="<?php echo get_stylesheet_directory_uri().'/img/404.jpg'; ?>" />
	</div>
	<div id="error">
		<center><h3>404 Not Found</h3></center>
	</div>
</div>

<?php get_footer(); ?>

Картинку в углу страницы положу в папку [SITE_DIR]/wp-content/themes/[THEME_NAME]/img/ , предварительно создав её.

GIT репозиторий