Изучаем WordPress

Загрузка WordPress

Делаем общую CSS для всех тем

Так как мы делаем свой, уникальный сайт, то будем делать и свой стиль. Чтобы не настраивать его каждый раз при тестировании новой темы (шаблона) мы сделаем в корне папку /kids/css, куда и будем загружать некоторые элементы стилей, которые мы бы хтели иметь независимо от шаблона, например, цвет заголовков и т.п. После этого, нам нужно для каждого шаблона, с которым мы экспериментируем, в файле header.php добавить перед тегом </head>строчку:

		<link rel="stylesheet" href="http://radiokidsfm/kids/css/site.css" type="text/css" media="screen, projection" />
		
	

Начинаем с разбора файловой структуры

После распаковки архива WordPress имеем следующий набор папок и файлов

Файловая структура WordPress

Все элементы, кроме выделенных красными прямоугольниками, составляют ЯДРО WP.


Первым загружается файл index.php. Вот его код:

							
<?php
	define('WP_USE_THEMES', true);

	/** Loads the WordPress Environment and Template */
	require( dirname( __FILE__ ) . '/wp-blog-header.php' );
							
						

Здесь определена переменная системы WP_USE_THEMES. Таблицу переменных системы составляем здесь. Затем загружается файл wp-blog-header.php.Вот его код:

							
<?php

 if ( !isset($wp_did_header) ) {

	$wp_did_header = true;

	// Load the WordPress library.
	require_once( dirname(__FILE__) . '/wp-load.php' );

	// Set up the WordPress query.
	wp();

	// Load the theme template.
	require_once( ABSPATH . WPINC . '/template-loader.php' );

}
							
						

Если файл wp-blog-header.php ещё не загружался (переменная-флажок $wp_did_header равна false), то загружаем библиотеку wp-load.php. Затем выполняем функцию wp - запуск WordPress. И. наконец, звгружаем шаблон wp-includes/template-loader.php.

Ниже приведена схема подключения (загрузки) файлов и выполнения функций внутри файла wp-blog-header.php.

			wp-blog-header.php
├── wp-load.php
│   ├── wp-config.php
│       ├── define DB params
│       └── wp-settings.php
│           ├── wp-includes/load.php
│           ├── wp-includes/default-constants.php
│           ├── wp-includes/version.php
│           ├── ... выполнение ряда wp-функций
│           ├── wp-includes/compat.php
│           ├── wp-includes/functions.php
│           ├── wp-includes/class-wp.php
│           ├── wp-includes/class-wp-error.php
│           ├── wp-includes/plugin.php
│           ├── wp-includes/pomo/mo.php
│           ├── ... выполнение ряда wp-функций
│           ├── wp-includes/default-filters.php
│           ├── wp-includes/ms-blogs.php
│           ├── wp-includes/ms-settings.php
│           ├── wp-includes/l10n.php
│       // Load most of WordPress.
│           ├── wp-includes/class-wp-walker.php
│           ├── wp-includes/class-wp-ajax-response.php
│           ├── wp-includes/formatting.php
│           ├── . . . . . .
│           ├── wp-includes/rest-api/class-wp-rest-server.php
│           ├── wp-includes/rest-api/class-wp-rest-response.php
│           ├── wp-includes/rest-api/class-wp-rest-request.php
│       // Load multisite-specific files.
│           ├── wp-includes/ms-functions.php
│           ├── wp-includes/ms-default-filters.php
│           ├── wp-includes/ms-deprecated.php
│       // Load must-use plugins.
│           ├── $mu_plugin
│       // Load network activated plugins. 
│           ├── $network_plugin
│           ├── ... выполнение ряда wp-функций
│       // Create common globals. 
│           ├── wp-includes/vars.php
│       // Load active plugins. 
│           ├── include_once( $plugin );
│       // Load pluggable functions. 
│           ├── wp-includes/pluggable.php
│           ├── wp-includes/pluggable-deprecated.php
│           ├── ... выполнение ряда wp-функций
│       // Fires before the theme is loaded. 
│           ├── do_action( 'setup_theme' );
│       // Define the template related constants. 
│           ├── wp_templating_constants(  );
│       // Load the default text localization domain. 
│           ├── require( $locale_file );
│           ├── wp-includes/locale.php
│       // Load the functions for the active theme, for both parent and child theme if applicable. 
│           ├── STYLESHEETPATH . '/functions.php
│           ├── TEMPLATEPATH . '/functions.php
│       // Fires after the theme is loaded. 
│           ├── do_action( 'after_setup_theme' );
│       // Set up current user. 
│           ├── $GLOBALS['wp']->init();
│       // Most of WP is loaded at this stage, and the user is authenticated. WP continues. 
│           ├── do_action( 'init' );
│       // Check site status. 
│           ├── require( $file );
│       // This hook is fired once WP, all plugins, and the theme are fully loaded and instantiated. 
│           ├── do_action( 'wp_loaded' );
├── wp()
│
└── wp-includes/template-loader.php
		├── . . .
		└── . . .
            
        

Загрузка констант, глобальных переменных и функций

Разбираем далее по шагам. Вот первая часть кода файла '/wp-load.php'

							
<?php

/** Define ABSPATH as this file's directory */
define( 'ABSPATH', dirname(__FILE__) . '/' );

error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );

 *
 * If neither set of conditions is true, initiate loading the setup process.
 */
if ( file_exists( ABSPATH . 'wp-config.php') ) {

	/** The config file resides in ABSPATH */
	require_once( ABSPATH . 'wp-config.php' );

} elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {

	/** The config file resides one level above ABSPATH but is not part of another install */
	require_once( dirname( ABSPATH ) . '/wp-config.php' );

} else {. . .}
							
						

Здесь определена переменная системы ABSPATH - абсолютный путь к корню системы. (Все переменные здесь).
Выполняем PHP-функцию вычисления уровня ошибок error_reporting
Далее ищем файл wp-config.php или в корне сайта, или на уровень выше.

Пояснение

ABSPATH . 'wp-config.php' - это следующий путь:
C:\OpenServer\domains\radiokidsfm/wp-config.php
dirname( ABSPATH ) . '/wp-config.php' - это другой путь на уровень выше:
C:\OpenServer\domains/wp-config.php

В нашем случае файл wp-config.php находится по первому адресу и он загружается.

Посмотрим, что там?

							
<?php
/**
 * Основные параметры WordPress.
 *
 * Скрипт для создания wp-config.php использует этот файл в процессе
 * установки. Необязательно использовать веб-интерфейс, можно
 * скопировать файл в "wp-config.php" и заполнить значения вручную.
 *
 * Этот файл содержит следующие параметры:
 *
 * * Настройки MySQL
 * * Секретные ключи
 * * Префикс таблиц базы данных
 * * ABSPATH
 *
 * @link https://codex.wordpress.org/Editing_wp-config.php
 *
 * @package WordPress
 */

// ** Параметры MySQL: Эту информацию можно получить у вашего хостинг-провайдера ** //
/** Имя базы данных для WordPress */
define('DB_NAME', 'radiokidsfm');

/** Имя пользователя MySQL */
define('DB_USER', 'root');

/** Пароль к базе данных MySQL */
define('DB_PASSWORD', '');

/** Имя сервера MySQL */
define('DB_HOST', 'localhost');

/** Кодировка базы данных для создания таблиц. */
define('DB_CHARSET', 'utf8');

/** Схема сопоставления. Не меняйте, если не уверены. */
define('DB_COLLATE', '');

/**#@+
 * Уникальные ключи и соли для аутентификации.
 *
 * Смените значение каждой константы на уникальную фразу.
 * Можно сгенерировать их с помощью {@link https://api.wordpress.org/secret-key/1.1/salt/ сервиса ключей на WordPress.org}
 * Можно изменить их, чтобы сделать существующие файлы cookies недействительными. Пользователям потребуется авторизоваться снова.
 *
 * @since 2.6.0
 */
define('AUTH_KEY',         'SPa$6_G^Q9Z?rjVSM6o*R!L_h:Pq(v}p^jGu~!aakq,AjG4zL}]>cQL^]i6T})e2');
define('SECURE_AUTH_KEY',  'KAt&%{(Q^;$iz+/t%{Ct0GZn7sh^QhO=UyZg@ub_4zY4ik^jZD2e|W*Z]q@Df+t;');
define('LOGGED_IN_KEY',    'rc*yzhDTux)yy]#KTB{gNivV<%J{aeOgJLY9?w2=)!btrM~8QdA,7C[h?n=7:W 4');
define('NONCE_KEY',        '8C$X7jh)r@QMN54seqvC6y|CU;o}Qg[A2|/x{,CFH0-7h,ZP|)1(WL$]nSc?kKz$');
define('AUTH_SALT',        'k.U[DOv6}[W,<P;8L!]l]tPTgA@7n(~R|f-lt7vLd_zc9nrO^:V-t;@j|}#H)p!U');
define('SECURE_AUTH_SALT', 'kd*Z+8(6CQu+xhm|phsRz`T=/=]#]&ck7oWmi33$W28@6O3D^a7H');

/**#@-*/

/**
 * Префикс таблиц в базе данных WordPress.
 *
 * Можно установить несколько сайтов в одну базу данных, если использовать
 * разные префиксы. Пожалуйста, указывайте только цифры, буквы и знак подчеркивания.
 */
$table_prefix  = 'wp_';

/**
 * Для разработчиков: Режим отладки WordPress.
 *
 * Измените это значение на true, чтобы включить отображение уведомлений при разработке.
 * Разработчикам плагинов и тем настоятельно рекомендуется использовать WP_DEBUG
 * в своём рабочем окружении.
 * 
 * Информацию о других отладочных константах можно найти в Кодексе.
 *
 * @link https://codex.wordpress.org/Debugging_in_WordPress
 */
define('WP_DEBUG', true);

/* Это всё, дальше не редактируем. Успехов! */

/** Абсолютный путь к директории WordPress. */
if ( !defined('ABSPATH') )
	define('ABSPATH', dirname(__FILE__) . '/');

/** Инициализирует переменные WordPress и подключает файлы. */
require_once(ABSPATH . 'wp-settings.php');
							
						

Здесь сначала вводятся параметры работы с БД. Это можно делать вручную в этом файле или через админовский интерфейс. Далее загружается файл wp-settings.php, который должен инициализировать переменные WordPress.
Вот начало кода этого файла:

							
<?php
/**
 * Used to set up and fix common variables and include
 * the WordPress procedural and class library.
 *
 * Allows for some configuration in wp-config.php (see default-constants.php)
 *
 * @internal This file must be parsable by PHP4.
 *
 * @package WordPress
 */

/**
 * Stores the location of the WordPress directory of functions, classes, and core content.
 *
 * @since 1.0.0
 */
define( 'WPINC', 'wp-includes' );

// Include files required for initialization.
require( ABSPATH . WPINC . '/load.php' );
require( ABSPATH . WPINC . '/default-constants.php' );
							
						

Здесь сначала вводятся определяется переменная WPINC - путь к директории wp-includes. Затем загружается файл /wp-includes/load.php, в котором определяется большое количество функций(функции можно посмотреть здесь).
Затем загружается файл /wp-includes/default-constants.php, в котором определяются константы и глобальные переменные, которые могут быть переопределены , в основном в wp-config.php.

Проблемы

Потребление ресурсов

Сайт загружается... загружается ... и никак не загрузится... Оказалось, что превышен лимит на оперативную память, установленный хостингом. Ищем причины превышения.

Как любая CMS, WordPress потребляет много ресурсов для собственного обслуживания, что не есть хорошо, но с этим приходится мириться... но нужно и бороться. Находим советы здесь
Прежде всего отключил сайт - дал возможность хостингу фиксировать снижение использования оперативной памяти. Включил, сайт заработал. Следую совету - установить в футере код

							
<?php echo get_num_queries(); ?> запросов. <?php timer_stop(1); ?> секунд. <?php echo memory_get_usage()/1024/1024, 2; ?> Мб
							
						

Открываю страницу просмотра кода сайта и в конце футера вижу ожидаемое сообщение:

							
34 запросов. 0,189 секунд. 14.1012039184572 Мб							
						

Вроде не так уж и страшно... хотя 34 запроса в секунду к БД и не очень мало... Решаю последовать советам, описанным здесь - почистить БД с помощью плагина WP Clean Up. Установил, почистил - он удаляет из базы ревизии постов и многое другое позволяет почистить, в частности транзитное кэширование (о котором можно прочитать здесь) - убирать его или нет - нужно решать для конкретного случая.

Теперь можно (и нужно!) убрать остатки таблиц в БД от неиспользуемых плагинов, которые подключались когда-то, но уже не используются. Для этого используем плагин WPDBSpringClean.

ВНИМАНИЕ! Перед чисткой БД с помощью этого плагина нужно сделать бэкап базы, а то можно удалить по ошибке что-нибудь лишнее!
Не знаю, пока, является ли частое обращение к БД причиной нагрузки на оперативную память, но почистить базу - не лишнее дело, нужно взять в привычку делать это на всех своих разработках на WordPress.

Проделаем то же самое с сайтом КПД. По ресурсам до чистки БД имеем:

							
61 запросов. 0,460 секунд. 16.0060806274412 Мб
							
						

После чистки с помощью WP Clean Up ничего не изменилось.

WPDBSpringClean не обнаружил остатков неиспользуемых плагинов.

Попробуем определить, какие из установленных плагинов в какой степени нагружают сервер с помощью плагина P3 - Plugin Performance Profiler.Установил. просканировал сайт - оказалось, что только этот плагин и грузил сайт на момент сканирования.

Загрузка векторных изображений

На одном из сайтов нам понадобилось, чтобы логотипы представленных там компаний, отображались в разных размерах и в одинаково хорошем качестве. Решили использовать логотипы в векторном исполнении. Но обнаружилась проблема - стандартная загрузка медиафайлов в WordPress воспринимает расширение .svg как недопустимый формат (по крайней мере на версии 4.7.3 и более ранних).

Есть много ссылок в интернете, как это преодолеть. Самый простой совет - вставить в function.php вашей темы следующий код:

							
// allow SVG uploads
add_filter('upload_mimes', 'custom_upload_mimes');
function custom_upload_mimes ( $existing_mimes=array() ) {
  $existing_mimes['svg'] = 'image/svg+xml';
  return $existing_mimes;
}
function fix_svg() {
    echo '<style type="text/css">
          .attachment-266x266, .thumbnail img {
               width: 100% !important;
               height: auto !important;
          }
          </style>';
 }
 add_action('admin_head', 'fix_svg');							
						

Это работает. Но так как уверенности в том, что это сработает во всех случаях не было, стали разбираться и проверили такую «хитрость». Загрузили логотип в формате .png. При загрузке через стандартную опцию «Медиафайлы» в папке /wp-content/uploads появилось несколько файлов изображения логотипа разных размеров, которые делает WordPress автоматически в соответствии с настройками темы.
Мы сделали векторные картинки логотипа таких же размеров и загрузили их в ту же папку с такими же именами, но с расширением .svg. Затем в базе данных в таблицах wp_posts, wp_postmeta нашли следы загруженного файла логотипа и заменили все .png на .svg. Например, в таблице wp_posts была запись со значением поля post_title соответствующим названию загруженного файла png-логотипа. В таблице wp_postmeta были обнаружены записи с ключами (meta_key) _wp_attached_file и _wp_attachment_metadata, в которых также располагались ссылки на файлы логотипа в поле meta_value. Везде заменили все .png на .svg. И это сработало! То же самое сделали и с иконкой (favicon).

Еще одна причина делать логотипы и иконки в векторе: WordPress и некоторые продвинутые темы и плагины WP формируют ссылки и метатеги для SEO в хёдере с использованием нашего фавикона и логотипа.

Например, мы обнаружили такие коды в шапке сайта, предназначенный для краулеров сторонних приложений:

							
<link rel="icon" href="http://dev.nedorub.com/wp-content/uploads/2017/03/cropped-favicon-32x32.png" sizes="32x32" />
<link rel="icon" href="http://dev.nedorub.com/wp-content/uploads/2017/03/cropped-favicon-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon-precomposed" href="http://dev.nedorub.com/wp-content/uploads/2017/03/cropped-favicon-180x180.png" />
<meta name="msapplication-TileImage" content="http://dev.nedorub.com/wp-content/uploads/2017/03/cropped-favicon-270x270.png" />							
							
						

Но после того, как мы проделали описанные выше манипуляции с таблицами БД, все .png заменились на .svg. А один из плагинов, например, сгенерировал скрипты, типа этого:

							
<script type='application/ld+json'>{"@context":"http:\/\/schema.org","@type":"Organization","url":"http:\/\/dev.nedorub.com\/","sameAs":[],"@id":"#organization","name":"SAN&SAN Studio","logo":"http:\/\/dev.nedorub.com\/wp-content\/uploads\/2017\/03\/logo-sanisan-300x23.png"}</script>							
						

Следы этой ссылки на логотип были обнаружены в таблице wp_options и .png исправлен на .svg.

Безопасность сайта

Как только мы выложили сайт с локального сервера на хостинг обнаружилась неприятная проблема: стал поступать спам двух видов - регистрация на сайте явных ботов и появление спамовских записей! Стали искать способы борьбы с ними.

Изменяем wp-login

Самый простой способ для разного рода вредителей войти в ваш сайт через wp-login.php, то есть через открытые «ворота» для регистрации и залогинивания.

Простейший способ уменьшить эту угрозу описан здесь. А именно: нужно сделать три шага:

  1. Переименовать файл wp-login.php, который находится в корне сайта. Например, в abcde.php
  2. Открыть только что переименованный файл и заменить везде wp-login.php на abcde.php
  3. В файле general-template.php, который находится в папке wp-includes, заменить wp-login.php на abcde.php

Но этого оказалось недостаточно. Так, при регистрации новых пользователей им отправлялось письмо с обратной ссылкой, содержащей wp-login.php. Чтобы ссылка была корректной, нужно также заменить wp-login.php на abcde.php в файле /wp-includes/plaggeble.php.

Блокируем доступ по wp-login.php и wp-admin

Подробно эта процедура описана здесь. Делаем это через файл .htaccess

							
# Hide admin URL start
<IfModule mod_rewrite.c>
RewriteEngine On
 
RewriteRule ^new_admin/?$ /new_wp-login.php?secret_key [R,L]
 
RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*$
RewriteRule ^blackhole/?$ /new_wp-login.php?secret_key&redirect_to=/wp-admin/ [R,L]
 
RewriteRule ^blackhole/?$ /wp-admin/?secret_key [R,L]
 
RewriteCond %{SCRIPT_FILENAME} !^(.*)admin-ajax\.php
RewriteCond %{HTTP_REFERER} !^(.*)my_site/wp-admin
RewriteCond %{HTTP_REFERER} !^(.*)my_site/new_wp-login\.php
RewriteCond %{HTTP_REFERER} !^(.*)my_site/blackhole
RewriteCond %{QUERY_STRING} !^secret_key
RewriteCond %{QUERY_STRING} !^action=logout
RewriteCond %{QUERY_STRING} !^action=rp
RewriteCond %{QUERY_STRING} !^action=postpass
RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*$
RewriteRule ^.*wp-admin/?|^.*new_wp-login\.php /not_found [R,L]
 
RewriteCond %{QUERY_STRING} ^loggedout=true
RewriteRule ^.*$ /new_wp-login.php?secret_key [R,L]
</IfModule>
# Hide admin URL end

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

							
						

Здесь new_admin - любой адрес, по которому теперь будет доступна страница входа в админ-панель сайта; new_wp-login.php - это тот новый файл, который мы сделали вместо wp-login.php на предыдущем шаге; my_site - домен нашего сайта и secret_key - любой сложный набор символов.

Внимание! Чтобы эти коды в .htaccess работали, мне пришлось отключить первоначальные коды, которые были прописаны в WP - первый модуль в скобках # BEGIN WordPress и # END WordPress, который я закоммитил с помощью символа #, но оставил в тексте для наглядности и напоминания.

Теперь вход на сайт возможен по адресу [my_site]/new_admin или [my_site]/new_wp-login.php?secret_key, а при попытке обратиться по адресам [my_site]/wp-admin или [my_site]/wp-login.php выдается 404 ошибка.

Удаляем readme.html

По присутствию этого файла в корне сайта и его содержанию злоумышленники выудят информацию о том, что ваш сайт сделан на WordPress и узнают версию движка. Поэтому следует просто удалить readme.html.

Удаляем meta-name Generator

Вордпресс добавляет внутри <head> метатеги <meta name="generator" content="WordPress 4.6.4" /> и <meta name="generator" content="WooCommerce 2.6.4" />, если подключен WooCommerce. Очевидно, что по этим метатегам также легко определить следы WordPress. Устраним их следующим образом. В файле /wp-includes/functions.php добавляем код

							
// Полностью убираем версию WordPress
						 
add_filter('the_generator', '__return_empty_string');
							
						

Удаляем версии из ссылок на css- и js-файлы

Версия WP также присутствует на ссылках типа
<link rel='stylesheet' id='dashicons-css' href='http://back2money.club/wp-includes/css/dashicons.min.css?ver=4.6.4' type='text/css' media='all' />. Устраним эти версии из ссылок следующим образом. В файле /wp-includes/functions.php добавим код

							
// Удаление параметра ver из добавляемых скриптов и стилей
 
function rem_wp_ver_css_js( $src ) {
    if ( strpos( $src, 'ver=' ) )
        $src = remove_query_arg( 'ver', $src );
    return $src;
}
 
add_filter( 'style_loader_src', 'rem_wp_ver_css_js', 9999 );
add_filter( 'script_loader_src', 'rem_wp_ver_css_js', 9999 );
							
						
Теперь та же ссылка выглядит без ?ver=4.6.4

Изменяем логотип на странице [my site]/wp-login.php

В оргигинале страница входа выглядит так:

Чтобы заменить логотип на свой, в файле нашей темы functions.php пропишем код, который это сделает, а именно:

							
function my_login_logo(){
   echo '
   <style type="text/css">
        #login h1 a { background: url('. get_bloginfo('template_directory') .'/images/my_logo.png) no-repeat 0 0 !important;width:211px !important; height:108px !important }
    </style>';
}
add_action('login_head', 'my_login_logo');
							
						

И, соответственно, в папку нашей темы images загружаем наш логотип с именем my_logo.php

Кроме того, чтобы при клике на логотип мы отправлялись на нашу главную страницу (а не на сайт WordPress), добавим еще две строчки кода в файл functions.php

							

add_filter('login_headerurl',create_function('','return get_home_url();'));
add_filter('login_headertitle',create_function('','return "San&San Studio";'));

							
						

Теперь форма залогинивания выглядит так:

Редактируем права пользователей

Для редактирования прав пользователей мы используем плагин User Role Editor. Подробнее о плагине написано здесь

После установки плгина появляется возможность редактировать права пользователя в настройках:

Первое, что мы делаем - устанавливаем роль пользовтеля по умолчанию, который впервые регистрируется еа сайте - это самая низшая роль - Подписчик.

Редактируем общие настройки

Многие спамят обратными ссылками с британских, французских, китайских и других сайтов.

Поэтому сейчас посмотрим, как отключить обратные ссылки в постах.

Обратные ссылки выглядят, как обычные комментарии – некто ставит на своих говносайтах ссылку на вашу статью, у вас в комментариях появляется цитата с этой ссылкой и ссылкой на чужой сайт. Эта ссылка обычно по-настоящему ужасна для вашего авторитета у поисковиков.

Вот, что видно в меню «Комментарии», и это только верхняя часть всего списка обратных ссылок, которые ожидают одобрения.

Меню Комментарии с обратными ссылками

Поближе это выглядит примерно так: какой-то бред, в который затесалась ссылка на ваш блог.

Комментарии с обратными ссылками

Во-первых, отключаем в блоге WordPress оповещения в/из других блогов об упоминаниях их в статьях. Во-вторых, отключаем обратные ссылки во всех уже опубликованных старых постах.

Никак не допишу статью о первоначальных настройках вордпресс-блога, а там будет информация и о «Настройках обсуждения». Поэтому пока просто переходим в админке в меню «Параметры» – «Обсуждения» и вверху страницы снимаем «галочки» в настройках для статьи по умолчанию:

  • «Пытаться оповестить блоги, упоминаемые в статье»
  • «Разрешить оповещения с других блогов (уведомления и обратные ссылки)»

Также можно включить опцию «Автоматически закрывать обсуждение статей старше столько-то дней».

Настройках обсуждения

Нажимаем внизу кнопку «Сохранить изменения».

Но на этом дело не закончиться, потому что для старых статей разрешены обратные ссылки.

Для одной статьи обратные ссылки отключить легко: нужно перейти к меню «Записи», нажать «Свойства» для нужной статьи и снять отметку «Разрешить отклики». После этого нажать кнопку «Обновить».

Разрешить отклики

Но если статей много, то проще всего изменить их свойства с помощью SQL-запроса в базе данных. Сделать это можно в панели phpMyAdmin или с помощью специальных плагинов WordPress.

Отключение обратных ссылок в старых статьях в панели phpMyAdmin

В панели phpMyAdmin выбираем нужную базу данных и переходим на вкладку «SQL».

SQL

В поле «Выполнить SQL-запрос(ы) к базе данных…» пишем такой запрос:

UPDATE wp_posts SET ping_status = 'closed';

Выполнить SQL-запрос

Здесь «UPDATE» - команда изменения данных в таблице, «wp _posts» - указание, что данные нужно поменять в таблице записей, «SET» - установка значения для «ping_status» (состояние обратных ссылок) как «closed» (закрыто).

После этого нажимаем кнопку «ОК» справа внизу, под полем для SQL-запросов. Если всё сделано правильно, то появится сообщение: «Затронуто столько-то строк…».

SQL-запрос

Это означает, что для всех записей блога обратные ссылки отключены, и спамеры со своими ссылками идут лесом.

А можно удалить сразу все комментарии, ожидающие одобрения, с помощью другого SQL-запроса к базе данных.

В этом случае запрос будет таким:

DELETE FROM wp_comments WHERE comment_type='trackback' ;

Здесь «DELETE» - команда на удаление строк, «FROM wp_comments» – из таблицы комментариев, «WHERE comment_type» - где тип комментария соответствует значению «trackback».

Делаем собственную тему (шаблон)

Начинаем с создания папки темы

Итак, мы уже знаем, что в файловой структуре Вордпресса имеется директория /wp-content/themes/, в которой размещены папки с наименованиями стандартных тем, поставленных в коробке Wordpress:

Расположение тем в файловой структуре WordPress

Интуитивно понимаем, что для создания собственной темы нам нужно здесь же разместить папку с названием нашей темы. Это и будет корневая папка нашей темы. Назовем тему (и соответственно папку), например: kidspromo.

Затем, как мы привыкли, создадим в этой новой папке файл index.php с традиционным приветствием Миру:

						
		<?php
		/**
		 * The main template file
		 *
		 * This is the most generic template file in a WordPress theme
		 * and one of the two required files for a theme (the other being style.css).
		 * It is used to display a page when nothing more specific matches a query.
		 * For example, it puts together the home page when no home.php file exists.
		 *
		 * @link http://codex.wordpress.org/Template_Hierarchy
		 *
		 */
			echo "Hellow World! I am index.php";
						
					
Комментарий к этому файлу мы позаимствовали из файла index.php стандартной темы. Изучим его внимательнее попозже.

Итак, если бы мы делали сайт без использования WP, то при переходе на сайт в браузере увидели бы наше приветствие. В данном же случае возникает естественный вопрос: а как же система увидит, что мы создали новую тему и хотим увидеть наше приветствие? Для активации темы мы должны в админке пройти в Внешний вид -> Темы

Создание папки собственной темы в файловой структуре WordPress

и там выбрать, и активировать нашу тему. Но если мы это сделаем, то обнаружим, что нашей темы там нет!

Оказывается, что простого создания папки с именем нашей темы - НЕДОСТАТОЧНО для того, чтобы WP обнаружил и предоставил администратору доступ к нашей теме.

Для этого в WP предусмотрена следующая процедура.

Размещаем в корне темы наряду с index.css файл style.css с вот таким комментарием:

						
		/*
		Theme Name: Kids Promo
		Theme URI: http://nedorub.com/wordpress-themes/kidspromo
		Description: Themes special for kidspromo.ru.
		Author: Sergey Nedorub
		Author URI: http://nedorub.com
		Version: 1.0.0
		License: GNU General Public License v2 or later
		License URI: http://www.gnu.org/licenses/gpl-2.0.html
		Tags: sergeynedorub, kidspromo, wordpress 
		Text Domain: sanradio
		*/

						
					

Оказывается, WordPress прочитает этот комментарий и разместит новую тему в админке.

Внимание! Название темы Theme Name- очень важно. Именно это название (в нашем случае Kids Promo) WordPress будет определять и выводить как название темы. Если мы делаем дочернюю тему, то описание несколько другое. О дочерних темах можно прочитать здесь
Заметки на будущее. Пропустить при певом прочтении.

При программировании сайта при необходимости можно вывести данные, размещенные в этом комментарии файла style.css с помощью функции wp_get_theme(). Вот что выдаёт эта функция с помощью php-кода print_r(wp_get_theme());:

					
				WP_Theme Object ( [update] => [theme_root:WP_Theme:private] => C:\OpenServer\domains\kidspromo/wp-content/themes [headers:WP_Theme:private] => Array ( [Name] => SanRadio [ThemeURI] => https://everpeek.com/wordpress-themes/sanradio [Description] => Themes special for radiokidsfm.ru. [Author] => Sergey Nedorub [AuthorURI] => https://www,everpeek.com [Version] => 1.0.0 [Template] => [Status] => [Tags] => light, blue, green, orange, pink, white, gray, red, black, one-column, two-columns, right-sidebar, left-sidebar, fluid-layout, responsive-layout, custom-background, custom-colors, custom-header, custom-menu, editor-style, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, threaded-comments, translation-ready [TextDomain] => sanradio [DomainPath] => ) [headers_sanitized:WP_Theme:private] => [name_translated:WP_Theme:private] => [errors:WP_Theme:private] => [stylesheet:WP_Theme:private] => sanradio [template:WP_Theme:private] => sanradio [parent:WP_Theme:private] => [theme_root_uri:WP_Theme:private] => [textdomain_loaded:WP_Theme:private] => [cache_hash:WP_Theme:private] => 7aa716ea677bf530f8db62f93fb73c59 )
					
				

Эти данные можно извлекать и использовать, например, с помощью такого php-кода:

						
		$my_theme = wp_get_theme( 'kidspromo' );
			if ( $my_theme->exists() ){
			echo $my_theme->get( 'Name' ) . " is version " . $my_theme->get( 'Version' );	
		}
						
					

Если теперь зайти в панели администратора WP в раздел выбора шаблонов Внешний вид > Темы, то можно увидеть, что появилась наша тема в списке прочих:

Выбор темы WordPress

Мы не поленимся и создадим еще файл-картинку нашей темы (размер 300 на 225 пикселей) и загрузим в папку kidspromo под именем screenshot.png. Теперь наша тема в разделе выбора тем в админке выглядит гораздо привлекательнее:

Выбор темы WordPress с превью

Активируем нашу тему и смотрим, что видит браузер при обращении к нашему сайту: Hellow World! I am index.php

Ура! наш файл index.php заработал!

Файловая структура

Теперь вернемся назад и прочитаем комментарий в файле index.php. Там написано, что этот файл является основным, и, например, выводится в качестве главной страницы, если нет файла home.php

Сделаем файл home.php с кодом:

						
		<?php
			/**
			 * The home.php file
			 *
			 */
			echo "Hellow World! I am home.php";
						
					

и перезагружаем сайт: видим, что выводится Hellow World! I am home.php. То есть, WordPress проигнорировал файл index.php и загрузил home.php !? Заметим здесь, что файл index.php не является обязательным и стандартные шаблоны WP его не используют.

Так вот! Оказывается, система WordPress распознает не только index.php но и ещё несколько специальных файлов-шаблонов и распоряжается с ними (выстраивает определенную иерархию и предоставляет к ним доступ из php-кодов) в соответствии со своим кодексом. Подробнее можно прочитать здесь.

К таким специальным файлам относятся:

  • header.php — содержит всё то, что находиться в верхушке сайта.
  • index.php — самое ядро темы, к нему крепяться все остальные части.
  • sidebar.php — содержит боковую панель (меню)
  • footer.php — всё то, что находится в подвале темы.
  • archive.php — шаблонный файл, который отображает когда были сделаны записи, авторы и тп.
  • single.php — шаблонный файл, который отвечает за загрузку одного поста (когда вы переходите на него по ссылке).
  • comments.php — прикрепляется к концу single.php, чтобы дать людям возможность оставлять комментарии
  • page.php — подобная single.php, но используется для WordPress страниц.
  • search.php — шаблонный файл, используется для отображения результатов поиска..
  • 404.php — шаблонный файл , сообщает об ошибке 404
  • style.css — все CSS-стили вашей темы
  • functions.php — файл используется для изменения функционала WordPress без изменения ядра движка.

Делаем главную страницу

Как мы описали выше, при загрузке сайта выводится страница home.php, а если её нет, то index.php. Но страница home.php не является обязательной. WP предусматривает два варианта выдачиглавной страницы сайта. Проследуем в админке по адресу Настройки -> Чтение:


Управление главной страницей - front-page

Здесь мы должны определить, что выводить на главной странице. Если мы выбираем «Ваши последние записи», то при загрузке сайта первой (главной) должна загружаться страница с нашими записями. Если выбираем «Статическую страницу», то активируются два поля со списками страниц сайта из которых нужно выбрать, какую страницу использовать в качестве главной (front-page), а на какой странице отображать последние записи. Но сначала, такие страницы нужно создать. Проследуем по адресу Страницы -> Добавить новую:


Добавление страницы в WordPress

Здесь мы можем ввести заголовок страницы и её содержание.

Следует заметить, что при установке WordPress создаются для примера - одна запись (Привет, мир! Добро пожаловать в WordPress. Это ваша первая запись. Отредактируйте или удалите её, затем пишите!), один комментарий на Привет, мир! и одна страница (ПРИМЕР СТРАНИЦЫ Это пример страницы... Успехов!).

Но для того, чтобы это все отображалось на сайте, необходимо разместить в корне темы файлы index.php, single.php и page.php, с правильно прописанными php-кодами для вывода постов, комментариев и страниц.

Начнем с файла index.php, который должен выводить все записи (посты). Создадим такой файл:

				
<?php
/**
 * The main template file
 * . . .
 */

get_header(); 
?>

	<?php
		while ( have_posts() ) : the_post();
	?>
		<article>
			<header>
				<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
			</header>
			<div>
				<?php the_content(); ?>
			</div>
		</article>
	<?php
		endwhile;
	?>

<?php get_footer();
				
			

Убедились, что при загрузке сайта (при настройке вывода на первой странице последних постов) выдается список постов.

Разберем вышенаписанный код.

Здесь используется несколько WP-функций, а именно: get_header() и get_footer() создают хёдер и футер HTML страницы и всавляют туда некоторые скрипты и ссылки, необходимые для функционирования системы (то есть для работы функций, хуков, тегов из арсенала Вордпресса). А также, что важно иметь ввиду, здесь отрабатывает главный запрос wp() и определяются глобальные переменные $wp_query, $wp_the_query;$query_string, $posts, $post, $request, $more и $single (для is_singular()), $authordata (для is_author()) и все переменные $wp_query. Цикл while ( have_posts() ) : the_post(); перебирает в БД записи из таблицы wp_posts и достает все записи, у которых значение поля post_type равно post. То есть все наши посты. Функция the_title() выдает заголовок поста, а функция the_content() - содержание поста.

Теперь сделаем файл-шаблон page.php, который по умолчанию будет являться шаблоном (базовым шаблоном) для вывода всех станиц сайта, для которых не задан другой шаблон. Создадим такой файл:

				
<?php
/**
 * The template for displaying all pages
 * . . .
 */

get_header(); 
?>

	<?php
		while ( have_posts() ) : the_post();
	?>
		<article>
			<header>
				<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
			</header>
			<div>
				<?php the_content(); ?>
			</div>
		</article>
	<?php
		endwhile;
	?>

<?php get_footer();
				
			

Здесь код такой же как и на странице index.php. Разница в том, что WordPress определяет, что это не пост, а страница и выбирает из таблицы wp_posts записи, у которых значение поля post_type равно page, а поле . То есть все наши посты.

Делаем header.php

Простейший код хёдера нашей темы может выглядеть так:

				
	<?php
	/**
	 * The header for our theme.
	 */
	?>
	<!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>
				
			

Заголовок Title

Чтобы в хёдере HTML кода появился заголовок Title можно его непосредственно прописать внутри <head></head>, но будет правильно использовать функционал WordPress. Вставим в файл нашей темы function.php следующую функцию:

				
					add_theme_support( 'title-tag' );
				
			

Подробнее об этой функции и ее возможностях (не только title-tag) подробно описано здесь. Теперь на каждой странице есть свой title, состоящей из названия страницы/поста и названия сайта.

Мета-теги description и keywords.

В настоящее время декларируется, что эти мета-теги не являются обязательными и не влияют на ранжирование сайта в поиске. Тем не менее, Яндекс, например, будет ругаться, если отсутствует тег описания сайта. Поэтому, установка этих тегов желательна.

Установить эти мета-теги можно либо с помощью плагинов, например: All in One SEO Pack, либо вручную: вставляем в хедере внутри <head> </head> следующий код, например:

				
	<meta name="description" content="<?php 
		  if ( is_front_page() || is_home() ) { 
		echo 'Разработка, продвижение и сопровождение сайтов - San&San Studio - ВЕБ Студия.';
	} elseif ( is_single() || is_page() ) {
		echo get_post_meta($post->ID, "description", true);
	} 
		remove_filter('term_description','wpautop');
		if (is_category()) {echo category_description();
	} ?>" />
	<meta name="keywords" content="<?php 
		  if ( is_front_page() || is_home() ) { 
		echo 'San&San Studio, Сергей Недоруб, создание сайтов, разработка сайтов, СЕО, SEO, продвижение сайта, поддержка сайта, разработка ИТ проектов';
	} elseif ( is_single() || is_page() ) {
		echo get_post_meta($post->ID, "keywords", true);
	} ?>" />				
			

Теперь в админке WP для каждой страницы и записи добавляем произвольные поля description и keywords и содержание этих полей. Как это сделать - подробно описано здесь.

Делаем меню

Если активировать нашу тему, то в разделе Внешний вид панели администратора увидим следующую картину:

А если активировать, например, тему Ribosome, то увидим такую картину:

Таким образом, наша тема пока не поддерживает ни Меню, ни Виджеты, ни Фон, ни Заголовок.
Все долгие поиски в интернете ответа на вопрос (и естественно, попыток этими ответами воспользоваться), не приносили успеха, пока я не наткнулся на статью Андрея Морковина. Следуя его инструкции, всё удалось настроить и научиться делать и подключать различные меню. Опишу подробнее. Начинаем с файла functions.php. Запишем в этом файле следующий сод:

				
// Регистрируем две области locations) для загрузки меню: header-menu1 и footer-menu1
function register_my_menus()
{
register_nav_menus
(
array( 'header-menu' => 'header-menu1', 'footer-menu' => 'footer-menu1')
);
}

// Инициируем подключение этих облостей при загрузке WordPress
if (function_exists('register_nav_menus'))
{
     add_action( 'init', 'register_my_menus' );
}

				
			

Перезагружаем тему и видим, что WordPress подключил нам функцию работы с меню.

Подпункт Меню в пункте Настроить в админ-панели WordPress

Создаём несколько меню (перед этим нужно создать несколько страниц, чтобы было, что добавлять в меню) и соотносим их к определенным областям - это несложно понять, поэкспериментировав с функцией Меню в админке. Мы создали два меню с именами: header-menu-2 и footer-menu-2. Чтобы вывести меню на сайте, нужно в соответствующем месте ( в нашем случае в файлах heder.phpfooter.php вставить в html-код, где мы хотим разместить меню кусок php-кода с вызовом меню wp-функцией wp_nav_menu():
в хёдере, например:

				
<div id="navigation">
	<div class="container">
		<div class="row">
			<div class="col-md-12">
			<nav class="navbar navbar-static-top" role="navigation">
			  <div class="container-fluid">
			    <div class="navbar-header">
			      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
			        <span class="sr-only">Toggle navigation</span>
			        <span class="icon-bar"></span>
			        <span class="icon-bar"></span>
			        <span class="icon-bar"></span>
			      </button>
			    </div>
			    <div class="navbar-collapse collapse" id="bs-example-navbar-collapse-1" style="height: 1px;">
     <?php wp_nav_menu( array( 'theme_location' => 'header-menu' ) ); ?>
			      			    </div>
			  </div>
			</nav>
			</div>
		</div>
	</div>
</div>
				
			

При загрузке файла WordPress генерирует HTML-код и вставляет его вместо wp_nav_menu(). Для нашего хёдера этот код имеет вид:

				
<div class="menu-header-menu-2-container">
	<ul id="menu-header-menu-2" class="menu"><li id="menu-item-247" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-70 current_page_item current_page_parent menu-item-247"><a href="http://test/index/">KIDSFM</a></li>
		<li id="menu-item-248" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-248"><a href="http://test/%d0%be-%d0%bd%d0%b0%d1%81/">О НАС</a></li>
		<li id="menu-item-249" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-249"><a href="http://test/%d1%88%d0%ba%d0%be%d0%bb%d0%b0/">ШКОЛА</a></li>
		<li id="menu-item-250" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-250"><a href="http://test/%d0%be-%d0%bd%d0%b0%d1%81/%d0%bd%d0%b0%d1%88-%d0%b0%d0%b4%d1%80%d0%b5%d1%81/">Наш адрес</a></li>
		<li id="menu-item-251" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-251"><a href="http://test/%d0%b0%d1%84%d0%b8%d1%88%d0%b0/">АФИША</a></li>
		<li id="menu-item-252" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-252"><a href="http://test/%d1%80%d0%b0%d0%b4%d0%b8%d0%be%d0%b2%d0%b5%d0%b4%d1%83%d1%89%d0%b8%d0%b5/">РАДИОВЕДУЩИЕ</a></li>
		<li id="menu-item-253" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-253"><a href="http://test/%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b8/">ПЕРЕДАЧИ</a></li>
		<li id="menu-item-254" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-254"><a href="http://test/%d1%82%d0%be%d0%bf/">ТОП</a></li>
		<li id="menu-item-255" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-255"><a href="http://test/%d0%b3%d0%b0%d0%bb%d0%b5%d1%80%d0%b5%d1%8f/">ГАЛЕРЕЯ</a></li>
	</ul>
</div>
				
			

Остаётся прописать стили для всех нужных классов меню, чтобы оно выглядело так, как нам нужно. Следует обратить внимание на класс current-menu-item, который должен определять стиль для кнопки меню, соответствующей текущей отображаемой странице... всё! Дело сделано!

Конечно, можно вставлять свой логотип в коды страниц сайта, где это требуется, простыми средствами HTML. Но это будет не правильно, если мы все-таки делаем WP-тему. Чтобы можно было загружать логотип из админки, нужно для начала вставить в functions.php следующий код:

				
		// Добавление в админке загрузки логотипа
		function wpb_custom_logo() {
		echo '
		
		';
		}
		 
		//хук в вывод шапки в административной панели
		add_action('wp_before_admin_bar_render', 'wpb_custom_logo');
				
			

Если теперь зайти в админке Внешний вид -> Настроить -> свойства сайта, то увидим, что появилась форма для загрузки логотипа:

Форма загрузки логотипа в админ-панели WordPress

Вставить логотип в коде можно теперь с помощью функции the_custom_logo(). А наименование сайта, введенного там же в Внешний вид -> Настроить -> свойства сайта - с помощью функции bloginfo('name').Например:

				
	<?php the_custom_logo()?><br>
	<a href="<?php bloginfo('url');?>" title="My Site"><?php bloginfo('name'); ?></a>
				
			

Делаем functions.php

Выше мы уже начали создавать файл functions.php, вставляя в него некоторые нужные нам функции для реализации определенных возможностей. Пора, как мне кажется, подробнее описать этот файл. Понятно, что как обычно мы в каком-то файле можем прописать различные функции, которые мы считаем нужными написать для облегчения программирования сайта. Для этого этот файл и предназначен. Но, так как мы работаем в WordPress, то в этом файле нужно прописать и определенные функции, открывающие возможности WordPress для нашей темы. Продолжим их создавать.

Настройка админки для Записей.

Зайдем в админке на Записи -> Добавить новую. Мы попадаем на страницу редактирования записи (post) и в правом сайдбаре видим следующее:

правый сайдбар на странице Добавить запись в админ панели WordPress

Но, если вы активируете стандартную тему, например Twentyseventeen, то увидите следующую картинку:

правый сайдбар на странице Добавить запись в админ панели WordPress

Сразу встает вопрос: почему в нашей теме нет возможности загружать Изображение записи и выбирать Формат записи? И как эти возможности добавить? Большинство рекомендаций в интернете сводится к тому, что нужно кликнуть на кнопку Настройка экрана и добавить нужные вам опции. Если вы это сделаете, например. в Twentyseventeen, то увидите следующее:

Настройка экрана на странице Добавить запись в админ панели WordPress

Но если вы сделаете то же самое в своей создаваемой теме, то обнаружите, что ни опции Формат, ни опции Изображение записи у вас нет! Что делать?

Для того, чтобы эти опции (и другие) поддерживались в вашей теме, нужно прописать такие возможности в файле functions.php:
				
/*
 * Enable support for Post Formats.
 *
 * See: https://codex.wordpress.org/Post_Formats
 */

if ( ! function_exists( 'kidspromo_theme_setup' ) ) :
/* Sets up theme defaults and registers support for various WordPress features. */
function kidspromo_theme_setup() {

    // языковая поддержка
    load_theme_textdomain( 'kidspromo', get_template_directory() . '/languages' );
    // фиды для rss-подписки
    add_theme_support( 'automatic-feed-links' );
    // добавление миниатюры поста
    add_theme_support( 'post-thumbnails' );
    // html5 форма поиска, форма и список комментариев
    add_theme_support( 'html5', array(
        'search-form', 'comment-form', 'comment-list',
    ) );
    // какие форматы постов будут поддерживаться
    add_theme_support( 'post-formats', array(
        'aside', 'image', 'video', 'quote', 'link', 'status',
    ) );
}
endif;
add_action( 'after_setup_theme', 'kidspromo_theme_setup' );
				
			

Поддержка виджетов

Чтобы в разделе левого меню админ панели Внешний вид появился подраздел Виджеты (управление виджетами) добавим аналогично тому, как это было сделано выше, следующий код в функцию functions.php

				
/**
 * Register widget area.
 *
 * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
 */
function my_theme_widgets_init() {
	register_sidebar( array(
		'name'          => __( 'Sidebar', 'my_theme' ),
		'id'            => 'sidebar-1',
		'description'   => __( 'Add widgets here to appear in your sidebar.', 'my_theme' ),
		'before_widget' => '<section id="%1$s" class="widget %2$s">',
		'after_widget'  => '</section>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );

	register_sidebar( array(
		'name'          => __( 'Footer 1', 'my_theme' ),
		'id'            => 'sidebar-2',
		'description'   => __( 'Add widgets here to appear in your footer.', 'my_theme' ),
		'before_widget' => '<section id="%1$s" class="widget %2$s">',
		'after_widget'  => '</section>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );

	register_sidebar( array(
		'name'          => __( 'Footer 2', 'my_theme' ),
		'id'            => 'sidebar-3',
		'description'   => __( 'Add widgets here to appear in your footer.', 'my_theme' ),
		'before_widget' => '<section id="%1$s" class="widget %2$s">',
		'after_widget'  => '</section>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );
}
add_action( 'widgets_init', 'my_theme_widgets_init' );
				
			

Заголовок Header Image

Теперь займёмся подключением функции Заголовка (Картинки заголовка). Для того, чтобы была возможность установить картинку заголовка для темы нужно включить опцию custom-header в функции add_theme_support(). Пропишем в файле functions.php следующий код:

				
/**
 * Set up the WordPress core custom header arguments and settings.
 *
 * @uses add_theme_support() to register support for 3.4 and up.
 * @uses sanfirst_header_style() to style front-end.
 * @uses sanfirst_admin_header_style() to style wp-admin form.
 * @uses sanfirst_admin_header_image() to add custom markup to wp-admin form.
 *
 * @since Sanfirst 1.0
 */
function sanfirst_custom_header_setup() {
	$args = array(
		// Text color and image (empty to use none).
		'default-text-color'     => 'EAEAEA',
		'default-image'          => '',

		// Set height and width, with a maximum value for the width.
		'height'                 => 292,
		'width'                  => 1144,
		'max-width'              => 2000,

		// Support flexible height and width.
		'flex-height'            => true,
		'flex-width'             => true,

		// Random image rotation off by default.
		'random-default'         => false,

		// Callbacks for styling the header and the admin preview.
		'wp-head-callback'       => 'sanfirst_header_style',
		'admin-head-callback'    => 'sanfirst_admin_header_style',
		'admin-preview-callback' => 'sanfirst_admin_header_image',
	);

	add_theme_support( 'custom-header', $args );
}
add_action( 'after_setup_theme', 'sanfirst_custom_header_setup' );
				
			

Этого достаточно, чтобы включить поддержку картинки заголовка для темы:

Теперь вставим в нужном месте HTML кода в хёдере вызов картинки заголовка:

				
<?php if( has_header_image() )
	echo  '<img src="'. get_header_image() .'" alt="'. get_bloginfo('title') .'">';
?>
				
			

В нашем случае картинку нужно было использовать как фон блока. Поэтому мы написали следующий код:

				
<div id="header" class="hidden-sm hidden-xs" style="background:url(<?php echo header_image() ?>); background-position:center;">
</div>
				
			

Здесь мы использовали функцию header_image(), которая выдаёт URL картинки.

Теперь встал вопрос о том, чтобы выводить эту картинку заголовка только на главной странице. Для этого мы поместили кодс выводом картинки внутри условного оператора:

				
<?php
if(is_home() OR is_page(91) ) {	?>

	<div id="header" ...>
	. . .
	</div>

<?php } ?>
				
			

Здесь мы использовали два условных тега: is_home() и is_page(). Причём тег is_page() можно использовать либо с ID страницы или с её наименованием, например:is_page(91) и is_page('АФИША') выдаёт один и тот же результат.

Как определить ID страницы?

  • Look in your browser status bar for the ID:
  1. Visit the related list table screen in your Administration Screen. For instance in the case of Posts visit Posts->All Posts, for Pages visit Pages->All Pages, and for Categories visit Posts->Categories.
  2. Now hover your mouse over the 'item' you need the ID. In the case of Pages, hover over that particular Page's title in the Title column and for Categories hover over the Categories Name in the Name column.
  3. Look at the status bar (at the bottom of your browser) and the you will find at the end of the line something like "post=123" or "tag_ID=67". In these cases, 123 is the Page ID, and 67 is the Category ID.
  • Install a plugin:
  1. Install and activate Reveal IDs for WP Admin or ShowID for Post/Page/Category/Tag/Comment.
  2. Find the ID displayed with each item.

Подключаем JS и CSS

Уже на этапе создания меню возникает вопрос о подключении скриптов и таблиц стилей. Если наше меню достаточно креативное и требует подключения скриптов .js и таблиц стилей .css, то возникает вопрос о их подключении. Первый вариант - просто прописать путь к этим файлам в хёдере и футере (что где нужно). И это работает. Но, так как мы делаем сайт на WP, то было бы правильно использовать средства вордпресса, тем более, что такие имеются.

Допусти, мы разместили необходимый нам скрипт my-script.js по адресу /assets/js/my-script.js. Для его подключения средствами WP поместим в файл functions.php нашей темы следующие функции:

				
/**
 * Enqueue scripts and styles.
 */
function mytheme_scripts() {
wp_register_script('my-script', get_template_directory_uri() . '/assets/js/my-script.js', array(),'1.0',true);
wp_enqueue_script('my-script');
}
add_action( 'wp_enqueue_scripts', 'mytheme_scripts' );
				
			

Функция wp_register_script() имеет 5 аргументов, разделенных запятыми. С первыми двумя понятно из контекста выше. третий параметр нужен, если для работы нашего скрипта требуется библиотека jquery. Тогда пишем array('jquery') вместо array(). Четвертый параметр - версия нашего скрипта - ставим что угодно. Пятый параметр указывает на размещение скрипта. Если это true, то скрипт будет размещен в футере, если false, то в хёдере. Если этот параметр отсутсвует, то скрипт будет помещен в хёдере.

Аналогично подключаем таблицу стилей:

				
/**
 * Enqueue scripts and styles.
 */
function mytheme_scripts() {
wp_register_script('my-script', get_template_directory_uri() . '/assets/js/my-script.js', array(),'1.0',true);
wp_enqueue_script('my-script');

wp_register_style('my-style', get_template_directory_uri() . '/assets/css/my-style.css');
wp_enqueue_style('my-style');
}
add_action( 'wp_enqueue_scripts', 'mytheme_scripts' );
				
			

Подробнее здесь.

Подключаем Font Awesome

Подключить иконки Fontawesome можно двумя способами (по крайней мере в моей практике). Первый - скачать неоходимые папки с файлами от разработчика fontawesome.ru, разместить эти папки на сайте и подключить файл font-awesome.min.css описанным выше способом.

Второй способ - разместить в файле темы style.css следующий код:

				
	@import url("https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css");
				
			

Я рекомендую второй способ по понятным причинам.

Настраиваем вход для пользователей

Если на сайте предусмотрен вход пользователей, то после корректной регистрации и авторизации WordPress отправляет всех пользователей на стандартную админ-панель. Для администраторов и редакторов сайта это нормально. Но обычных пользователей, которые привыкли к интерфейсу типа Вконтакте, админ-панель WordPress вводит в состояние ступора и ужаса. Если ваш заказчик портала для общения сосвоими клиентами увидит один раз эту админ-панель, то больше видеть её не захочет. Встает вопрос: как после аутентификации напривлять пользователей на другую станицу сайта, а не на админ-панель?

Для этого достаточно в файле темы functions.php добавить следующую функцию:

				
add_filter('login_redirect', '_myplugin_lgn_redirect');

function _myplugin_lgn_redirect() {
   return '/some-page-on-my-website';
}
				
			

Настраиваем вход для пользователей в зависимости от роли

Часто возникает необходимость перенаправлять пользователей после авторизации на разные страницы сайта в зависимости от роли пользователя. Для этого в файл темы functions.php достаточно добавить функцию:

				
function my_redirect_users_by_role() {
  
    $current_user   = wp_get_current_user();
    $role_name      = $current_user->roles[0];
  
    if ( 'subscriber' === $role_name ) {
        wp_redirect( 'http://yoursite.com/dashboard' );
    } // if
  
} // my_redirect_users_by_role
add_action( 'admin_init', 'my_redirect_users_by_role' );
				
			

А лучше так:

				
function my_redirect_users_by_role() {
  
    if ( ! defined( 'DOING_AJAX' ) ) {
  
        $current_user   = wp_get_current_user();
        $role_name      = $current_user->roles[0];
  
        if ( 'subscriber' === $role_name ) {
            wp_redirect( 'http://yoursite.com/dashboard' );
        } // if $role_name
  
    } // if DOING_AJAX
  
} // my_redirect_users_by_role
add_action( 'admin_init', 'my_redirect_users_by_role' );
				
			

Эти коды заимствованы отсюда. И хотя авторы предлагают использовать их в специальном плагине, но, оказывается, они работают и при простом размещении в файле functions.php.

Редирект с произвольной страницы сайта

Иногда возникает задача перенаправлять пользователя с произвольной страницы сайта на другую. Например, я хочу закрыть доступ неаутентифицированным пользователям на страницу account.php. Стандартная функция wp-redirect() для этого не пригодна. Вот такой код работать не будет:

				
 
if(!is_user_logged_in()){ wp-redirect('http://my_site.com')}

				
			

Для этих целей я использую следующий код:

				
if(!is_user_logged_in()){ 
<script>document.location.href = 'http://my_site.com';</script>
}
				
			

Подробнее можно прочитать здесь.

Подключаем плагины

Первы плагин, который мы подключали и учились подклчать и активировать плагины, был TablePress. Нам просто понадобилось сделать красивую табличку на одной из страниц (О НАС).

Последовательность действий: 1 - скачиваем папку с архивом плагина, например, отсюда https://wordpress.org/plugins/tablepress/; 2- разархивируем и содержимое помещаем в папку /wp-content/plagins/; 3- заходим в раздел "Плагины" в левом меню админ-панели, ищем только-что подгруженный плагин и активируем его. Псле обновления в левом меню админ-панели появился раздел "TablePress":

Внимание! Некоторые плагины не отображаются в виде отдельного раздела в меню адмн-панели, но видны в разделе "Настройки", откуда и следует ими управлять и настраивать.

Кроме того, что появился раздел "TablePress" в меню админ-панели, при создании или редактирвании постов и страниц появилась новая кнопочка в редакторе:

.

Здесь можно вставлять таблицу в текст и её редактировать. Подробнее здесь.

Сайдбары - это контейнеры для вставки виджетов. Они могут быть вставлены в любом месте на сайте (не обязательно сбоку) функцией

				
 ?lt;php get_sidebar('[имя сайдбара]'); ?>
				
			

Но для того, чтобы это работало, нужно 1 - сначала создать в корне шаблона файл sidebar-[имя сайдбара].php и вставить в него следующий код:

				
 <?php if ( function_exists ( dynamic_sidebar(4) ) ) : ?>
<?php dynamic_sidebar (4); ?>
<?php endif; ?>				
			

где 4 - это номер сайдбара (по-порядку). Затем 2 - в файле functions.php добавить описание этого сайдбара:

				
/** Регистрируем сайдбары  */
if ( function_exists('register_sidebar') )
	register_sidebar(array(
		'before_widget' => '',
		'after_widget' => '',
		'before_title' => '<h3>',
		'after_title' => '</h3>',
	));
 
register_sidebar( array(
'name' => '[имя сайдбара 1]',
) );
 
register_sidebar( array(
'name' => '[имя сайдбара 2]',
) );
. . .
register_sidebar( array(
'name' => '[имя сайдбара 4]',
) );
				
			

Строим страницу постов (index.php)

После вывода хёдера начинаем строить вывод постов. Примерный код страницы index.php может выглядеть так:

				
<?php
/**
 * The main template file
 */

get_header(); ?>

		<div class="wrap">
			<?php if ( is_home() && ! is_front_page() ) : ?>
				<header class="page-header">
					<h1 class="page-title"><?php single_post_title(); ?></h1>
				</header>
			<?php else : ?>
			<header class="page-header">
				<h2 class="page-title">
				<?php _e( 'Posts' ); ?>
				<?php echo "Page title" ?></h2>
			</header>
			<?php endif; ?>

			<div id="primary" class="content-area">
				<main id="main" class="site-main" role="main">
					<?php
					if ( have_posts() ) :

						/* Start the Loop */
						while ( have_posts() ) : the_post(); 

							/*
							 * Include the Post-Format-specific template for the content.
							 * If you want to override this in a child theme, then include a file
							 * called content-___.php (where ___ is the Post Format name) and that will be used instead.
							 */
							get_template_part( 'template-parts/post/content', get_post_format() );
						endwhile;

					else :

						get_template_part( 'template-parts/post/content', 'none' );

					endif;
					?>

				</main><!-- #main -->
			</div><!-- #primary -->
			<?php //get_sidebar(); ?>
		</div><!-- .wrap -->
<?php get_footer();
				
			

Здесь в цикле while сначала с помощью условного тега have_posts() проверяем наличие посов для данной страницы в БД. Если посты есть, запускаем цикл их выдачи.
Если посты есть, то они начинают выводиться в цикле while ..., при этом на каждом витке цикла сначала устанавливается индекс поста с помощью функции the_post() (подробнее об этой функции можно прочитать здесь), после чего в нашем случае выполняется функция get_template_part( ). Эта функция WP загружает в шаблон часть шаблона, а именно в нашем сучае, файл content.php, который находится в папке /template-parts/post/.
В этой части шаблона мы, собственно, задаем то, что именно хотим вывести и делаем html разметку.
Вот примерно так может выглядеть код файла (content.php):

				
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
	<header class="entry-header">
		<?php
			if ( is_single() ) {
				the_title( '<h1 class="entry-title">', '</h1>' );
			} elseif ( is_front_page() && is_home() ) {
				the_title( '<h3 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h3>' );
			} else {
				the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
			}
		?>
	</header><!-- .entry-header -->

	<?php if ( '' !== get_the_post_thumbnail() && ! is_single() ) : ?>
		<div class="post-thumbnail">
			<a href="<?php the_permalink(); ?>">
				<?php the_post_thumbnail( '...' ); ?>
			</a>
		</div><!-- .post-thumbnail -->
	<?php endif; ?>

	<div class="entry-content">
		<?php
			/* translators: %s: Name of current post */
			the_content( sprintf(
				__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', '...' ),
				get_the_title()
			) );

			wp_link_pages( array(
				'before'      => '<div class="page-links">' . __( 'Pages:', '...' ),
				'after'       => '</div>',
				'link_before' => '<span class="page-number">',
				'link_after'  => '</span>',
			) );
		?>
	</div><!-- .entry-content -->
</article><!-- #post-## -->
				
			

Условный тег is_home() определет, находимся ли мы на главной странице?
Здесь следует обратить внимание на то, что такое Главная страница? Главной страницей в WP называется страница, на которой выводятся посты (записи). А страница, которая выводится первой при обращении к сайту по адресу http://my_site, является страницей Front_page. Таким образом, на главной странице is_home()==1, а на первой странице is_front_page()==1.

В админ-панели можно настроить, какая страница будет Home, а какая Front-page. Для этого перейдём в Настройки => Чтение
Настройки-чтение

Если установить «отображать - Ваши последние записи», то автоматически страница с выводом постов становится и Home, и Front_page. Если мы хотим, как в нашем случае, первой загружать страницу KIDSFM, то выбираем «отображать - Статическая страница» и выбираем, какая страница будег Front, а какая Home. Как показано на рисунке, у нас первой будет загружаться KIDSFM, а записи (посты) будут выводиться на странице ЛЕНТА
Теперь разберём, что такое sticky? Оказывается, можно «прилепить» запись на странице home, тогда эта запись будет отображаться в верхней части страницы записей, а новые записи будут отображаться ниже. Естественно, для такой прилепленной записи имеет смысл оформить стили, отличные от текущих записей. В нашем случае мы для этого и используем шаблон /template-parts/sticky.php.

Чтобы «прилепить» запись, нужно перед её публикацией поставить галочку в «Прилепить на главную страницу»

Настройки-чтение
Затем сохранить и опубликовать.


Навигация по записям на index.php

Так как постов (записей) может быть очень много, то нам нужно выводить определенное их количество и иметь возможность выводить следующее количество и так далее - то, что мы называем навигацией по записям

Для этого добавим в файле index.php функцию the_posts_pagination():

			
<?php
if ( have_posts() ) :

	/* Start the Loop */
	while ( have_posts() ) : the_post(); 

		get_template_part( 'template-parts/post/content', get_post_format() );

	endwhile;

the_posts_pagination( array(
	'prev_text' => '<i class="fa fa-arrow-left"></i>' . '<span class="screen-reader-text">' . 'предыдущая страница' . '</span>',
	'next_text' => '<span class="screen-reader-text">' . 'следущая страница' . '</span>' . '<i class="fa fa-arrow-right"></i>',
	'before_page_number' => '<span class="meta-nav screen-reader-text">' . 'Страница' . ' </span>',
) ); 

else :
	get_template_part( 'template-parts/post/content', 'none' );
endif;
?>
				
		

Сколько постов выводить - настроим в админке: Настройки -> Чтение

Настройки-Чтение-На странице блога выводить не более

Теперь на странице постов выводятся первые четыре поста и строка навигации:

Первая страница постов

Если кликнуть по цифре 2 в строке навигации, то будут выданы следующие четыре поста:

Вторая страница постов
и т.д.

Навигация по записям на произвольной странице

Если нам требуется выводить посты на произвольной странице, например, на статической главной странице, то описанные выше коды не будут работать, так как функция the_post() не определит наличие записей для этой страницы.

В этом случае требуются следующие коды

				
<?php
// 1 значение по умолчанию
//$paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1; // Вариант для не статической страницы
$paged = (get_query_var('page')) ? get_query_var('page') : 1; // Вариант для статической страницы
//echo "Мы на странице:". $page ." на главной странице блога, указанной как статическая.";
$the_query = new WP_Query( array(
	'posts_per_page' => 4,
	//'category_name'  => 'artist',
	'post_type' => 'post',
	'paged'          => $paged,
) );

// цикл вывода полученных записей
while( $the_query->have_posts() ){
	$the_query->the_post();
	?>
		<!-- HTML каждой записи -->
 	<?php 
} ?>

<?
wp_reset_postdata();

// пагинация для произвольного запроса
$big = 999999999; // уникальное число

echo paginate_links( array(
	'base'    => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
	'format'  => '?paged=%#%',
//	'current' => max( 1, get_query_var('paged') ),  //вариант для не статической страницы
	'current' => max( 1, get_query_var('page') ),  //   Вариант для статической страницы
	'total'   => $the_query->max_num_pages
) );
?>
				
		


Делаем Шаблон страницы

Итак, нам понадобилась страница, для которой не подходят базовые шаблоны В WP существует возможность создания собственных шаблонов. Пусть страница называется, например, РАДИОВЕДУЩИЕ. Для этой страницы мы делаем свой шаблон. Для этого создаём в корне темы файл presenters.php, заходим в админ панели на редактирование этой страницы и видим, что справа в разделе Атрибуты -> Шаблоны появился выбор шаблона Presenters.

Настройки-чтение

Его и выбираем! Далее в страницу presenters.php вставляем код, который будет выводить посты из категории (рубрики) ведущие. Это стандартный код вывода постов, но вначале добавляем условие того, что выводятся посты только данной рубрики:

				
<?php
	if (is_page('93') ) {
		$cat = array(16);
	} elseif ( is_page('16') ) {
		$cat = array(32);
	} elseif ( is_page('28') ) {
		$cat = array(17);
	} else {
		$cat = '';
	}

	$showposts = -1; // -1 shows all posts
	$do_not_show_stickies = 1; // 0 to show stickies
	$args=array(
	   'category__in' => $cat,
	   'showposts' => $showposts,
	   'caller_get_posts' => $do_not_show_stickies
	   );
	$my_query = new WP_Query($args); 

?>
				
			

Здесь 93 - ID страницы РАДИОВЕДУЩИЕ, а 16 - ID рубрики Ведущие.

Чтобы определить ID страницы, нужно перейти в админке в раздел СТРАНИЦЫ, навести курсор на название нужной страницы и внизу экрана появится ссылка, содержащая этот ID. Аналогично определяется ID рубрики и поста.

Как видим один шаблон можно использовать для разных страниц и выводить на них разные посты.

Исключение рубрики из HOME.page

После того, как мы начали делать записи в рубрике ведущие оказалось, что эти записи появляются как посты на страницк ЛЕНТЫ, то есть на странице home, но нам этого не нужно. Вста вопрос, как исключить показ постов из этой рубрики на странице home. Один вариант, который мы нашли - вставить в файл functions.php следующий код:

				
/**
 *  Исключаем категорию с ID=33 из показа в ленте
 *
*/ 
 function exclude_category($query) {
if ( $query->is_page ) {
$query->set('category__not_in', array(33));}
return $query;
}
add_filter('pre_get_posts', 'exclude_category');
				
			

Но это, как ни странно - не помогло. А помогло вот что: в файле index.php перед строкой

				
<?php if ( have_posts() ) : ?>
				
			

нужно вставить строку, чтобы получилось вот так:

				
        <?php if (is_home()) { query_posts('cat=-33'); } ?>
		<?php if ( have_posts() ) : ?>				
			
По идее должны работать и такие конструкции:
  • query_posts(‘cat=-3’) — Не показывать категорию id которой равно 3;
  • query_posts(‘cat=-1,-2,-3’) — Не показывать категории, id которых равны 1, 2 и 3;
  • query_posts(‘cat=2,6,17’) — Вывести категории с id равным 2, 6 и 17;
  • query_posts(‘category_name=WordPress’) — Вывести категорию с названием “WordPress”;
  • query_posts(‘name=Hello World’) — Вывести один пост с названием “Hello World”;
  • query_posts(‘p=5’) — Вывести один пост, id которого равно 5;
  • query_posts(‘page_id=7’) — Вывести страницу id которой равно 7;
  • query_posts(‘pagename=about’) — Вывести страницу с названием “about”;
  • query_posts(‘cat=18&showposts=5’) — Вывести 5 постов из категории с id=18;
  • query_posts(‘cat=3&orderby=date&order=ASC’) — Вывести посты из категории id которой равно 3, сортировать по дате в хронологическом порядке(DESC — в обратном порядке);
  • query_posts(‘posts_per_page=10’) — Вывести 10 постов на страницу (при значении -1 выводит все посты);
  • query_posts(‘cat=3&year=2008’) — Вывести посты из категории с id=3 за 2008 год;
  • query_posts(‘orderby=rand&showposts=3&cat=3’) — выводин рандомно, т.е. случайно 3 записи из 3 категории;
  • query_posts(‘orderby=rand&showposts=3’) — выводит случайно 3 записи из всех категорий;
  • query_posts(‘meta_key=cars&meta_value=volvo’) — выводит список постов с произвольным полем “cars” и значением этого поля volvo.
    Информация о примерах использования query_posts взята с сайта http://www.wp-info.ru/
    Будьте осторожны, если не до конца уверены в том что делаете.
  • Добавляем и/или редактируем роли

    Теперь нам потребовалось ведущим делегировать определенные права, то есть создать новую роль - "Ведущий".
    В WP предусмотрены базовые роли:

    • Administrator
    • Editor
    • Author
    • Contributor
    • Subscriber

    Что в русскоязычном варианте WP выглядит как:

    • Администратор
    • Редактор
    • Автор
    • Участник
    • Подписчик

    Данные о ролях и их правах хранятся в БД в таблице wp_options в записи с option_name = wp_user_roles в поле option_value в виде следующей строки:

    				
    a:6:{s:13:"administrator";a:2:{s:4:"name";s:13:"Administrator";s:12:"capabilities";a:93:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;s:12:"edit_plugins";b:1;s:10:"edit_users";b:1;s:10:"edit_files";b:1;s:14:"manage_options";b:1;s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:6:"import";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:8:"level_10";b:1;s:7:"level_9";b:1;s:7:"level_8";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:12:"delete_users";b:1;s:12:"create_users";b:1;s:17:"unfiltered_upload";b:1;s:14:"edit_dashboard";b:1;s:14:"update_plugins";b:1;s:14:"delete_plugins";b:1;s:15:"install_plugins";b:1;s:13:"update_themes";b:1;s:14:"install_themes";b:1;s:11:"update_core";b:1;s:10:"list_users";b:1;s:12:"remove_users";b:1;s:13:"promote_users";b:1;s:18:"edit_theme_options";b:1;s:13:"delete_themes";b:1;s:6:"export";b:1;s:22:"tablepress_edit_tables";b:1;s:24:"tablepress_delete_tables";b:1;s:22:"tablepress_list_tables";b:1;s:21:"tablepress_add_tables";b:1;s:22:"tablepress_copy_tables";b:1;s:24:"tablepress_import_tables";b:1;s:24:"tablepress_export_tables";b:1;s:32:"tablepress_access_options_screen";b:1;s:30:"tablepress_access_about_screen";b:1;s:29:"tablepress_import_tables_wptr";b:1;s:23:"tablepress_edit_options";b:1;s:24:"NextGEN Gallery overview";b:1;s:19:"NextGEN Use TinyMCE";b:1;s:21:"NextGEN Upload images";b:1;s:22:"NextGEN Manage gallery";b:1;s:19:"NextGEN Manage tags";b:1;s:29:"NextGEN Manage others gallery";b:1;s:18:"NextGEN Edit album";b:1;s:20:"NextGEN Change style";b:1;s:22:"NextGEN Change options";b:1;s:24:"NextGEN Attach Interface";b:1;s:14:"ure_edit_roles";b:1;s:16:"ure_create_roles";b:1;s:16:"ure_delete_roles";b:1;s:23:"ure_create_capabilities";b:1;s:23:"ure_delete_capabilities";b:1;s:18:"ure_manage_options";b:1;s:15:"ure_reset_roles";b:1;s:22:"edit_tablepress_tables";b:1;s:29:"edit_others_tablepress_tables";b:1;s:25:"publish_tablepress_tables";b:1;s:30:"read_private_tablepress_tables";b:1;}}s:6:"author";a:2:{s:4:"name";s:6:"Author";s:12:"capabilities";a:20:{s:12:"upload_files";b:1;s:10:"edit_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:4:"read";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;s:22:"delete_published_posts";b:1;s:22:"tablepress_edit_tables";b:1;s:24:"tablepress_delete_tables";b:1;s:22:"tablepress_list_tables";b:1;s:21:"tablepress_add_tables";b:1;s:22:"tablepress_copy_tables";b:1;s:24:"tablepress_import_tables";b:1;s:24:"tablepress_export_tables";b:1;s:32:"tablepress_access_options_screen";b:1;s:30:"tablepress_access_about_screen";b:1;s:19:"moderate_quick_chat";b:1;}}s:11:"contributor";a:2:{s:4:"name";s:11:"Contributor";s:12:"capabilities";a:5:{s:12:"delete_posts";b:1;s:10:"edit_posts";b:1;s:7:"level_0";b:1;s:7:"level_1";b:1;s:4:"read";b:1;}}s:6:"editor";a:2:{s:4:"name";s:6:"Editor";s:12:"capabilities";a:44:{s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:22:"tablepress_edit_tables";b:1;s:24:"tablepress_delete_tables";b:1;s:22:"tablepress_list_tables";b:1;s:21:"tablepress_add_tables";b:1;s:22:"tablepress_copy_tables";b:1;s:24:"tablepress_import_tables";b:1;s:24:"tablepress_export_tables";b:1;s:32:"tablepress_access_options_screen";b:1;s:30:"tablepress_access_about_screen";b:1;s:19:"moderate_quick_chat";b:1;}}s:10:"subscriber";a:2:{s:4:"name";s:10:"Subscriber";s:12:"capabilities";a:3:{s:4:"read";b:1;s:7:"level_0";b:1;s:19:"moderate_quick_chat";b:1;}}}
    				
    			

    Это текстовая строка в специальном формате, в котором WP хранит данные о массивах и их элементах. Подробнее об этом фрмате можно посмотреть здесь.
    Как английские наименования превращаются в русские - изучим позже, когда будем разбираться с локализацией. А сейчас займёмся созданием новой роли. Конечно, можно попробовать просто в эту строку в БД вписать тупо новую роль, но мы хотим, чтобы администратор мог это делать из панели администратора, поэтому мы подключили новый плагин - User Role Editor.
    У этого плагина, как оказалось, много возможностей и работает он хорошо, но смущает то, что в БД он прописывает странную длину строки наименования роли, если она написана кириллицей, например: s:14:"Ведущий". То есть, длина строки 14 символов, хотя в слове "Ведущий" их 7! Подозревая, что это может отобразиться на корректности работы функций WP, которые работают с ролями, будем поступать так: писать наименования латиницей, а потом займемся локализацией WP и будем ручками добавлять наименование роли на русском или другом языке.

    Вход на сайт - редактируем

    После залогинивания (входа) пользователя, WP выводит его на админ-панель, что очень плохо для нормального сайта, а не блога! Поэтому стоит задача, выводить пользователя на нужную страницу сайта в зависимости от его роли.
    После тестирования разных вариантов, оказалось, что нормально работает код, описанный в WP Codex, который нужно вставить в functions.php файл темы:

    				
    
    				
    			

    Плагины WordPress

    Плагин User Role Editor

    Убираем бокс, позволяющий редакторам изменять ник в процессе чата, то есть писать сообщения под другим ником:

    Плагин Quick Chat

    Убираем бокс, позволяющий редакторам изменять ник в процессе чата, то есть писать сообщения под другим ником:

    Для этого в админке в настройках чата убираем галочку:

    При этом у тех пользователей,которым мы дали права модерировать чат остается возможность менять ник.

    Теперь убираем дату и время в чате.

    				
    <div class="quick-chat-history-timestring">'+
    a.timestring+'</div>
    				
    			

    в файле quick-chat/js/quick-chat-core.js

    После подключения плагина регистрации в ВК обнаружилась проблема - в качестве имени участника чата плагин использует логин, что плохо! Нужно сделать так, чтобы высвечивалось Имя Фамилия. Делаем.
    В файле плагина /wp-content/plugins/quick-chat/quick-chat.php изменяем два куска кода:

    				
    
                global $current_user;
                get_currentuserinfo();
    
                if(isset($_COOKIE['quick_chat_alias_'.$current_user->ID])){
                    $this->user_name =  stripslashes($_COOKIE['quick_chat_alias_'.$current_user->ID]);
                } else{
                    setcookie('quick_chat_alias_'.$current_user->ID, $current_user->user_login, 0, COOKIEPATH, COOKIE_DOMAIN);
                    $this->user_name =  $current_user->user_login;
                }
    
    			. . . . . 
    
                    if($username_bad_words == 0 && (!is_user_logged_in() || (is_user_logged_in() && strcasecmp($_POST['username_check'], $current_user->user_login) != 0))){
    			
    				
    			

    Меняем на:

    				
    
                global $current_user;
                get_currentuserinfo();
                $chat_name = $current_user->first_name.' '.$current_user->last_name;
    
                if(isset($_COOKIE['quick_chat_alias_'.$current_user->ID])){
                    $this->user_name =  stripslashes($_COOKIE['quick_chat_alias_'.$current_user->ID]);
                } else{
                    setcookie('quick_chat_alias_'.$current_user->ID, $chat_name, 0, COOKIEPATH, COOKIE_DOMAIN);
                    $this->user_name =  $chat_name;
                }
    
    			. . . . .
    			
                    if($username_bad_words == 0 && (!is_user_logged_in() || (is_user_logged_in() && strcasecmp($_POST['username_check'], $chat_name) != 0))){
    
    				
    			

    Пользователи должны почистить куки!!!

    Изменяем интервал времени отключения пользователя за неактивность. Дело в том, что плагин удаляет окно чата, если пользователь не участвует какое-то время в переписке. Нам понадобилось вывести чат ведущим, но при этом они не долны в нем участвовать по определению. Чтобы чат не отключался - просто увеличим время отклчения.
    Для этого в файле wp-content/plugins/quick-chat/js/quick-chat-core.js находим строчку

    				
    
    quick_chat.users_interval&&(quick_chat.users_interval=setInterval(function(){quick_chat.update_users()},1E3*quick_chat.timeout_refresh_users));
    
    				
    			

    и меняем 1E3 на 1E6, например. Или поступаем проще: идем в админку и в настройках Quick Chat изменяем параметр в соответствующем блоке:






    Плагин TablePress

    Кроме того, что появился раздел "TablePress" в меню админ-панели, при создании или редактирвании постов и страниц появилась новая кнопочка в редакторе:

    .

    Здесь можно вставлять таблицу в текст и её редактировать. Вот пример такой таблицы (как она выглядит):

    Очень полезный и хороший плагин - РЕКОМЕНДУЕМ!!!

    Плагин Meta Slider

    Мы протестировали несколько плагинов для создания слайдеров. а именно: banner-slider, len-slider,ml-slider. Первые два забраковали, а Мета слайдер вполне подошёл: простые настройки, наличие шорт-кода, возможность устанавливать лбые размеры и прочее - очень простой и вполне достаточен. Можно создавать несколько слайдеров и вставлять как в постах и страницах, так и в сайд-барах с помощьюсоответствующего виждета. Вот пример php-кода, который мыиспользовали для вставки двух баннеров на страницах:

    				
    <?php if(is_page(70) OR is_page('РАДИОВЕДУЩИЕ') ) {	
    ?>
    <div id="top-advertising" class="hidden-sm hidden-xs">
    	<div class="container" style="position: relative;">
            <div class="row">
                <div class="col-md-12">
    			<?php echo do_shortcode("[metaslider id=344]"); ?>
                </div>
            </div>
    	</div>
    </div>
    <?php } else {?>
    
    <div id="top-advertising" class="hidden-sm hidden-xs">
    	<div class="container" style="position: relative;">
            <div class="row">
                <div class="col-md-12">
    			<?php echo do_shortcode("[metaslider id=348]"); ?>
                </div>
            </div>
    	</div>
    </div>
    <?php } ?>
    <!-- Top Banner -->
    				
    			

    При создании слайд-баннера ему автоматически присваивается ID, который видно в настройках Meta Slider в разделе "Использование" - там приводится как шорт-код, так и php-код для вставки в шаблон.

    Плагин Full Width Background Slider

    Этот слайдер создает изменяющийся бэкграунд страницы. Смотрится привлекательно. При его активации в редактировании страниц и постов появляется новая настройка

    и можно выбрать - показывать его на данной странице - или нет.

    Этот слайд-бэкграунд автоматически подключается к странице выдачи постов, то есть к index.php. Чтобы не показывать его на этой странице мы вставили в коде этой страницы перед подключением футера (именно в футере этот плагин подключает скрипт и ссылки на картинки для баннера) написали следующий стиль для блока с картинками:
    				
    . . .
    <style type="text/css" media="screen">
    <!--
    #fwbslider{display:none !important;}
    	-->
    <!--
    a.fwb_fromthis {display:none !important;}
    	-->	
    </style>
    <?php get_footer(); ?>
    . . .
    				
    			
    Кроме того, мы убрали вывод логотипа производителя с сылкой на его сайт, вставив в странице page.phpследующий стиль для этого логатипа:
    				
    				. . .
    <style type="text/css" media="screen">
    <!--
    a.fwb_fromthis {display:none !important;}
    	-->
    </style>
    	
    <?php get_footer(); ?>
    				. . .
    				
    			

    Вцелом, не очень ясно где и для чего его использовать этот слайдер для фона страниц?

    Плагин NextGEN Gallery













    БД WordPress

    Cтруктура строки массивов

    Массивы и их значения хранятся в БД в виде строк специального формата, например:
    a:5:{s:13:"administrator";a:2:{s:4:"name";s:13:"Administrator";s:12:"capabilities";a:93:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;. . .
    Разберем, что мы видим:

    • a:N:{ это начало массива, где "N" – количество элементов массива. Например, "a:5:{" в начале строки означает, что массив состоит из пяти элементов.
    • s:N:"строка"; – "s" это строковый тип, N – количество символов в строке. Например, s:6:"author";
    • b:1; – означает логический (Boolean) тип со значением "1" or "True" (Истина)

    Такая строка получается из массива с помощью php-функции serialize(). Например, из массива $new_role_array:

    				
    $new_role_array = Array ( 'editor' => 1, 'shop' => 0 );
    $new_role_string = serialize($new_role_array);
    echo $new_role_string; 
    				
    			

    получаем строку $new_role_string:

    				
    	a:2:{s:6:"editor";i:1;s:4:"shop";i:0;}
    				
    			








    Разберём шаблон twentysixteen

    Первым загружается файл index.php. Вот его код:

    							
    <?php
    /**
     * The main template file
     *
     * This is the most generic template file in a WordPress theme
     * and one of the two required files for a theme (the other being style.css).
     * It is used to display a page when nothing more specific matches a query.
     * E.g., it puts together the home page when no home.php file exists.
     *
     * @link http://codex.wordpress.org/Template_Hierarchy
     *
     * @package WordPress
     * @subpackage Twenty_Sixteen
     * @since Twenty Sixteen 1.0
     */
    
    get_header(); ?>
    
    	<div id="primary" class="content-area">
    		<main id="main" class="site-main" role="main">
    
    		<?php if ( have_posts() ) : ?>
    
    			<?php if ( is_home() && ! is_front_page() ) : ?>
    				<header>
    					<h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
    				</header>
    			<?php endif; ?>
    
    			<?php
    			// Start the loop.
    			while ( have_posts() ) : the_post();
    
    				get_template_part( 'template-parts/content', get_post_format() );
    
    			// End the loop.
    			endwhile;
    
    			// Previous/next page navigation.
    			the_posts_pagination( array(
    				'prev_text'          => __( 'Previous page', 'twentysixteen' ),
    				'next_text'          => __( 'Next page', 'twentysixteen' ),
    				'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'twentysixteen' ) . ' </span>',
    			) );
    
    		// If no content, include the "No posts found" template.
    		else :
    			get_template_part( 'template-parts/content', 'none' );
    
    		endif;
    		?>
    
    		</main><!-- .site-main -->
    	</div><!-- .content-area -->
    
    <?php get_sidebar(); ?>
    <?php get_footer(); ?>
    		
    	

    В этом коде вызываются 9 функций, а именно:

    # Имя фунции Source File Описание
    1 get_header() wp-includes/general-template.php. the header.php template file from your current theme's directory. If a name is specified then a specialised header header-{name}.php will be included. If the theme contains no header.php file then the header from the default theme wp-includes/theme-compat/header.php will be included.
    2 have_posts() wp-includes/query.php This function checks to see if the current WordPress query has any results to loop over. This is a boolean function, meaning it returns either TRUE or FALSE..
    3 single_post_title() wp-includes/general-template.php Display or retrieve page title for post. This is optimized for single.php template file for displaying the post title. It does not support placing the separator after the title, but by leaving the prefix parameter empty, you can set the title separator manually. The prefix does not automatically place a space between the prefix, so if there should be a space, the parameter value will need to have it at the end..
    4 the_post() wp-includes/query.php. Iterate the post index in The Loop. Retrieves the next post, sets up the post, sets the 'in the loop' property to true.
    5 get_template_part wp-includes/general-template.php Load a template part into a template Makes it easy for a theme to reuse sections of code in a easy to overload way for child themes. Includes the named template part for a theme or if a name is specified then a specialised part will be included. If the theme contains no {slug}.php file then no template will be included. The template is included using require, not require_once, so you may include the same template part multiple times. For the $name parameter, if the file is called “{slug}-special.php” then specify “special”..
    6 get_post_format() wp-includes/post-formats.php Retrieve the format slug for a post
    7 the_posts_pagination wp-includes/link-template.php Display a paginated navigation to next/previous set of posts, when applicable.
    8 get_sidebar() wp-includes/general-template.php Load sidebar template. Includes the sidebar template for a theme or if a name is specified then a specialised sidebar will be included. For the parameter, if the file is called “sidebar-special.php” then specify “special”.
    9 get_footer() wp-includes/general-template.php the footer.php template file from your current theme's directory. if a name is specified then a specialised footer footer-{name}.php will be included. If the theme contains no footer.php file then the footer from the default theme wp-includes/theme-compat/footer.php will be included.

    Первая функция get_header() вставляет файл header.php из нашего шаблона. Как он должен выглядеть? Посмотрим, например, хёдер из шаблона Twentysixteen:

    							
    <?php
    /**
     * The template for displaying the header
     *
     * Displays all of the head element and everything up until the "site-content" div.
     *
     * @package WordPress
     * @subpackage Twenty_Sixteen
     * @since Twenty Sixteen 1.0
     */
    
    ?><!DOCTYPE html>
    <html <?php language_attributes(); ?> class="no-js">
    <head>
    	<meta charset="<?php bloginfo( 'charset' ); ?>">
    	<meta name="viewport" content="width=device-width, initial-scale=1">
    	<link rel="profile" href="http://gmpg.org/xfn/11">
    	<?php if ( is_singular() && pings_open( get_queried_object() ) ) : ?>
    	<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>">
    	<?php endif; ?>
    	<?php wp_head();?>
    </head>