Создание адаптивного меню с помощью фреймворка Bootstrap и привязка его к CMS WordPress

А далее пойдет подробная пошаговая схема для внедрения компонента. Итак поехали. Урок1, поэтому начинаем с самого нуля. Вкратце установка WP:
Скачиваем русскую версию WordPress с официального сайта https://ru.wordpress.org/
Устанавливаем локальный сервер, СУБД, PHP — эта связка называется xAMP, где x — Linux, Windows или MAC в зависимости от вашей платформы.

A — Apache, M — MySql, P — PHP. Найдите в интернете готовую сборку для своей платформы, скачайте и установите.
У меня ОС Windows, в качестве сборки использую Денвер, либо OpenServer.
Запускаем локальный сервер и приступаем к работе. Как вариант, можете работать прямо на хостинге, но я предпочитаю работать на локальной машине.
Для установки WordPress — находим папку со всеми вашими сайтами и распаковываем туда скачанный архив с WordPress, у меня это папка: Z:\home\localhost\www
Я создал новую папку и назвал ее webproject, туда распаковал архив.
Далее заходим в браузер и открываем страничку http://localhost/webproject/ — появляется web-установщик WordPress.
Первым делом надо создать базу данных для вашего нового сайта. Это придется сделать вручную. Заходим в утилиту phpmyadmin. Я скачивал свежую версию с оф. сайта, так как в денвере
устаревшая версия. И скопировал утилиту в новую папку phpmyadmin. Теперь утилита доступна у меня по адресу: http://localhost/phpmyadmin/
По умолчанию юзер root без пароля. Для локальной машины пойдет. Если разворачиваете сервер, или работаете на хостинге, обязательно ставьте пароль.
Создаем новую базу данных, я назвал также как и имя проекта webproject
Далее можно возвращаться к нашему веб-установщику. Вводите все необходимый данные, следуете по шагам, вводите имя сайта и прочую информацию, и все готово!
Сайт на CMS WordPress установился и доступен по адресу: http://localhost/webproject/
Осталось только определиться с шаблоном. Если делаете сайт на заказ, попробуйте подобрать подходящей вашей тематике шаблон на wordpress в интернете.
Далее вам останется только немного подредактировать ваш шаблон, неважно выбрали вы платный или бесплатный, мои уроки будут вам полезны, потому что вы возможно захотите
какой-то веб-компонент добавить, либо подправить, ну и собственно будете понимать сам принцип программирования для CMS WordPress.

Мы же будем делать проект с нуля, так что и для новичка все будет понятно. А для веб-разработчика будет достаточно просто взять готовый код с проекта и внедрить компонент по шагам.
Итак, возьмем стандартную тему WordPress, например тему twentysixteen, скопируем ее и создадим в этой же папке с темами папку MyTheme и все содержимое скопируем туда.
Вот и все, мы получили нашу собственную тему, теперь активируем ее в админке. В дальнейшем я отключил в functions.php файл стилей темы style.css, так что смысла от этой темы не осталось)
Нам надо было изначально взять пустую тему underscores.me — впринципе мы получили практически тоже самое, но там еще есть кое-какие плюшки, например файлик сброса стилей который не меняет
отображение. Так что если читаете статью, а не делаете по видео, можете скачать тему underscores http://underscores.me/, если же читаете статью уже позже, то неважно, продолжаем работать так)
С базовой средой определились, все дальнейшие уроки будут наращивать эту базу, и далее уже пойдет информация по пошаговому внедрению для конкретного урока:ШАГ1

Скачиваем Bootstrap c официального сайта! http://getbootstrap.com/
Можно скачать прямо с главной страницы сборку по умолчанию. Скачивайте версию Bootstrap где написано «Bootstrap
Compiled and minified CSS, JavaScript, and fonts. No docs or original source files are included.»ШАГ2

Подключаем Bootstrap к нашему сайту на CMS WordPress
Все подключения для сайта на CMS WordPress нужно производить в файле functions.php. Вообще старайтесь придерживаться стиля программирования такого же как в официальных темах WP,
у них сделано именно так. Находим в файле functions.php функции для подключения стилей и скриптов — wp_enqueue_style и wp_enqueue_script. Код для подключения стилей Bootstrap:

// Bootstrap stylesheet
wp_enqueue_style( 'bootstrap-style', get_template_directory_uri(). '/libs/bootstrap/css/bootstrap.min.css' );	

Все дополнительно подключаемые библиотеки будем складывать в папку libs/
Подключаем скрипт Bootstrap:

// Bootstrap javascript
wp_enqueue_script( 'bootstrap-js', get_template_directory_uri() . '/libs/bootstrap/js/bootstrap.min.js', array('jquery'), '' );

ШАГ 3

Подключаем наш файлик стилей и наш файл скриптов. Обязательно подключайте эти файлы в самом конце, для того чтобы они переопределяли стили бутстрапа и прочих библиотек.
Вот код для подключения наших кастомных файлов для стилей. Ну и сразу подключим файл media.css для задания стилей для различных разрешений экрана.
Не забудьте создать 2 этих файла и скопировать в папку css нашей темы. Файл style.css может быть пустым.

//our theme style.css
wp_enqueue_style( 'mytheme-style', get_template_directory_uri(). '/css/style.css', array(), '' );	
//media css theme
wp_enqueue_style( 'mytheme-style-media', get_template_directory_uri(). '/css/media.css', array('mytheme-style'), '' );	

А вот вам шаблон для файла медиа-запросов media.css с использованием сетки Bootstrap:

/*==========  Desktop First Method  ==========*/

/* Large Devices, Wide Screens */
@media only screen and (max-width : 1200px) {

}

/* Medium Devices, Desktops */
@media only screen and (max-width : 992px) {
	
}

/* Small Devices, Tablets */
@media only screen and (max-width : 768px) {
	
}

/* Extra Small Devices, Phones */
@media only screen and (max-width : 480px) {
	
}

/* Custom, iPhone Retina */
@media only screen and (max-width : 320px) {

}


/*==========  Mobile First Method  ==========*/

/* Custom, iPhone Retina */
@media only screen and (min-width : 320px) {

}

/* Extra Small Devices, Phones */
@media only screen and (min-width : 480px) {

}

/* Small Devices, Tablets */
@media only screen and (min-width : 768px) {
	
}

/* Medium Devices, Desktops */
@media only screen and (min-width : 992px) {

}

/* Large Devices, Wide Screens */
@media only screen and (min-width : 1200px) {

}

И еще ниже подключим наш кастомный файл стилей. Закиньте его в папку js темы и назовите common.js к примеру.
Вот подключение:

//подключение нашего скрипта js
wp_enqueue_script( 'my-script', get_template_directory_uri() . '/js/common.js', array( 'jquery' ));

ШАГ 4

С подключениями закончили, теперь давайте перейдем к html-разметке для меню. Находим файл в котором выводится меню. В нашем случае менюшка выводится в хедере сайта.
Открываем файл header.php внутри шаблона и правим код для меню следующим образом.
Разметка для меню:

<section class="nav_section">
     <div class="container">
      <div class="row">
       <div class="col-md-12">

<nav class="navbar navbar-default main_nav">

   <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
  <span class="sr-only">Toggle navigation</span>
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
      </button>
   </div>

   <!-- Collect the nav links, forms, and other content for toggling -->
   <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <?php /* Primary navigation */
      wp_nav_menu( array(
 'menu' => 'top_menu',
 'depth' => 2,
 'container' => false,
 'menu_class' => 'nav navbar-nav',
   //Process nav menu using our custom nav walker
 'walker' => new wp_bootstrap_navwalker())
      );
      ?>
   </div><!-- /.navbar-collapse -->
 
</nav>

   </div>
  </div>
 </div>
</section>

Таким образом мы преобразовали верстку меню в соответствии с тем как выводится меню Bootstrap.ШАГ5

Далее скачиваем класс для меню, написанный программистом, вот его адрес на github: https://github.com/twittem/wp-bootstrap-navwalker
Класс меню Bootstrap для WordPress wp_bootstrap_navwalker.php:

<?php

/**
 * Class Name: wp_bootstrap_navwalker
 * GitHub URI: https://github.com/twittem/wp-bootstrap-navwalker
 * Description: A custom WordPress nav walker class to implement the Bootstrap 3 navigation style in a custom theme using the WordPress built in menu manager.
 * Version: 2.0.4
 * Author: Edward McIntyre - @twittem
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 */

class wp_bootstrap_navwalker extends Walker_Nav_Menu {

 /**
  * @see Walker::start_lvl()
  * @since 3.0.0
  *
  * @param string $output Passed by reference. Used to append additional content.
  * @param int $depth Depth of page. Used for padding.
  */
 public function start_lvl( &$output, $depth = 0, $args = array() ) {
 $indent = str_repeat( "\t", $depth );
 $output .= "\n$indent<ul role=\"menu\" class=\" dropdown-menu\">\n";
 }

 /**
  * @see Walker::start_el()
  * @since 3.0.0
  *
  * @param string $output Passed by reference. Used to append additional content.
  * @param object $item Menu item data object.
  * @param int $depth Depth of menu item. Used for padding.
  * @param int $current_page Menu item ID.
  * @param object $args
  */
 public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
 $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

 /**
  * Dividers, Headers or Disabled
  * =============================
  * Determine whether the item is a Divider, Header, Disabled or regular
  * menu item. To prevent errors we use the strcasecmp() function to so a
  * comparison that is not case sensitive. The strcasecmp() function returns
  * a 0 if the strings are equal.
  */
 if ( strcasecmp( $item->attr_title, 'divider' ) == 0 && $depth === 1 ) {
 $output .= $indent . '<li role="presentation" class="divider">';
 } else if ( strcasecmp( $item->title, 'divider') == 0 && $depth === 1 ) {
 $output .= $indent . '<li role="presentation" class="divider">';
 } else if ( strcasecmp( $item->attr_title, 'dropdown-header') == 0 && $depth === 1 ) {
 $output .= $indent . '<li role="presentation" class="dropdown-header">' . esc_attr( $item->title );
 } else if ( strcasecmp($item->attr_title, 'disabled' ) == 0 ) {
 $output .= $indent . '<li role="presentation" class="disabled"><a href="#">' . esc_attr( $item->title ) . '</a>';
 } else {

 $class_names = $value = '';

 $classes = empty( $item->classes ) ? array() : (array) $item->classes;
 $classes[] = 'menu-item-' . $item->ID;

 $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );

 if ( $args->has_children )
 $class_names .= ' dropdown';

 if ( in_array( 'current-menu-item', $classes ) )
 $class_names .= ' active';

 $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

 $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
 $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

 $output .= $indent . '<li' . $id . $value . $class_names .'>';

 $atts = array();
 $atts['title']  = ! empty( $item->title ) ? $item->title : '';
 $atts['target'] = ! empty( $item->target ) ? $item->target : '';
 $atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';

 // If item has_children add atts to a.
 if ( $args->has_children && $depth === 0 ) {
 $atts['href']    = '#';
 $atts['data-toggle'] = 'dropdown';
 $atts['class'] = 'dropdown-toggle';
 $atts['aria-haspopup'] = 'true';
 } else {
 $atts['href'] = ! empty( $item->url ) ? $item->url : '';
 }

 $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );

 $attributes = '';
 foreach ( $atts as $attr => $value ) {
 if ( ! empty( $value ) ) {
 $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
 $attributes .= ' ' . $attr . '="' . $value . '"';
 }
 }

 $item_output = $args->before;

 /*
  * Glyphicons
  * ===========
  * Since the the menu item is NOT a Divider or Header we check the see
  * if there is a value in the attr_title property. If the attr_title
  * property is NOT null we apply it as the class name for the glyphicon.
  */
 if ( ! empty( $item->attr_title ) )
 $item_output .= '<a'. $attributes .'><span class="glyphicon ' . esc_attr( $item->attr_title ) . '"></span> ';
 else
 $item_output .= '<a'. $attributes .'>';

 $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
 $item_output .= ( $args->has_children && 0 === $depth ) ? ' <span class="caret"></span></a>' : '</a>';
 $item_output .= $args->after;

 $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
 }
 }

 /**
  * Traverse elements to create list from elements.
  *
  * Display one element if the element doesn't have any children otherwise,
  * display the element and its children. Will only traverse up to the max
  * depth and no ignore elements under that depth.
  *
  * This method shouldn't be called directly, use the walk() method instead.
  *
  * @see Walker::start_el()
  * @since 2.5.0
  *
  * @param object $element Data object
  * @param array $children_elements List of elements to continue traversing.
  * @param int $max_depth Max depth to traverse.
  * @param int $depth Depth of current element.
  * @param array $args
  * @param string $output Passed by reference. Used to append additional content.
  * @return null Null on failure with no changes to parameters.
  */
 public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
        if ( ! $element )
            return;

        $id_field = $this->db_fields['id'];

        // Display this element.
        if ( is_object( $args[0] ) )
           $args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );

        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

 /**
  * Menu Fallback
  * =============
  * If this function is assigned to the wp_nav_menu's fallback_cb variable
  * and a manu has not been assigned to the theme location in the WordPress
  * menu manager the function with display nothing to a non-logged in user,
  * and will add a link to the WordPress menu manager if logged in as an admin.
  *
  * @param array $args passed from the wp_nav_menu function.
  *
  */
 public static function fallback( $args ) {
 if ( current_user_can( 'manage_options' ) ) {

 extract( $args );

 $fb_output = null;

 if ( $container ) {
 $fb_output = '<' . $container;

 if ( $container_id )
 $fb_output .= ' id="' . $container_id . '"';

 if ( $container_class )
 $fb_output .= ' class="' . $container_class . '"';

 $fb_output .= '>';
 }

 $fb_output .= '<ul';

 if ( $menu_id )
 $fb_output .= ' id="' . $menu_id . '"';

 if ( $menu_class )
 $fb_output .= ' class="' . $menu_class . '"';

 $fb_output .= '>';
 $fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">Add a menu</a></li>';
 $fb_output .= '</ul>';

 if ( $container )
 $fb_output .= '</' . $container . '>';

 echo $fb_output;
 }
 }
}

Положите этот класс в папку с вашей темой.ШАГ6

Впринципе все. Заполняйте в админке вашу менюшку и все уже будет выводиться. Вам осталось только поработать со стилями.
Ну и давайте еще сделаем нашу менюшку прилипающей. То есть при прокрутке до определенного места меню будет становиться фиксированной вверху экрана.
javascript-код для того, чтобы сделать меню прилипающим. Пропишите в вашем кастомном файле скриптов common.js:

jQuery(document).ready(function($) {

if(window.matchMedia('(max-width: 1200px)').matches && window.matchMedia('(min-width: 993px)').matches)
{
    $('.nav_section').affix({
     offset: 150
    });
  }
  else if(window.matchMedia('(max-width: 992px)').matches && window.matchMedia('(min-width: 481px)').matches)
  {
   $('.nav_section').affix({
     offset: 220
    });
  }
  else if(window.matchMedia('(max-width: 480px)').matches)
  {
   $('.nav_section').affix({
     offset: 220
    });
  }
  else{
   $('.nav_section').affix({
   offset: 120
   });
  }
 

 if ( $('.nav_section').hasClass("affix") ) {

 $('.nav_section').addClass('stickyBar');

 }

 $('.nav_section').on('affixed-top.bs.affix', function () {
 //alert('Fired!');
 $(this).addClass('staticBar');
 $(this).removeClass('stickyBar');
 $('button.orderCallBtn').removeClass('btnSticky');
 });

 $('.nav_section').on('affixed.bs.affix', function () {
 //alert('Fired!');
 $(this).addClass('stickyBar');
 $(this).removeClass('staticBar');
 $('button.orderCallBtn').addClass('btnSticky');
 });

});

ШАГ 7

Также еще нужно поработать со стилями меню. В файле стилей нашей темы style.css пропишем:

.affix {
    top: 0;
}
section.nav_section{
 background: #f8f8f8;
 height: 52px;
 width: 100%;
 z-index: 10;
 border-top:1px solid #ccc;
 border-bottom:1px solid #ccc;
}
 section.nav_section nav.main_nav{
 position: relative;
 }
 div.navbar-collapse{
 z-index: 220;
 }
 .navbar-default {
 border: 0;
 }

ШАГ 8

Самый главный шаг забыли. Нужно зарегистрировать кастомный класс в файле functions.php вашей темы. Добавьте следующий код:

require_once('wp_bootstrap_navwalker.php');

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