Очумелые ручки! Строим галерею с «бэком» на WordPress и фронтом на fancybox 3

Йоу-йоу! Работал я над сайтом компании, которая занимается производством домов из древесины. Им очень хотелось сделать сайт с огромным количеством фотографий и сделать это на одной странице с разделением на несколько галерей. Дело это всё «крутиться» на WordPress’е. А сейчас уже работает как часики) Так, что погнали

Нам понадобится

Да-да! Всё как в очумелых ручках! Так вот, нам понадобится:

  1. Рабочий сайт на WordPress
  2. Плагин real.PostImages (для добавления картинок к записи)
  3. Подключенный jQuery 3
  4. Подключенный fancybox 3

Подготовка

Нужно создать папку, в которой будет хранится весь наш код внутри темы. Я у себя создал папку modiles > fancy-gallery. А там создал файлы: index.php и app.js. И подключил в function.php

// Подключение index.php
if(file_exists(get_template_directory() . "/modules/fancy-gallery/index.php")){
    require_once get_template_directory() . "/modules/fancy-gallery/index.php";
}
// Подключение app.js
wp_enqueue_script( 'application', get_template_directory_uri() . '/js/app.js', array('gjQuery', 'fancybox'), '0.1.0', true );

О том как правильно подключать скрипты в wordpress вы можете прочитать в моей статье в моей статье.

Шаг 1. Создание произвольного типа записи

Это нужно для того, чтобы можно было в админке создавать несколько галерей. Так что в index.php пишем

add_action('init', 'fgb_fs_materials');
function fgb_fs_materials(){
    register_post_type('x_gallery', array(
        'labels'             => array(
            'name'               => 'xGallery', // Основное название типа записи
            'singular_name'      => 'xGallery', // отдельное название записи типа 
            'add_new'            => 'Add item',
            'add_new_item'       => 'Add item',
            'edit_item'          => 'Edit item',
            'new_item'           => 'New item',
            'view_item'          => 'View item',
            'search_items'       => 'Search',
            'not_found'          =>  'Not found',
            'not_found_in_trash' => 'No Material found in the basket',
            'parent_item_colon'  => '',
            'menu_name'          => 'xGallery'

        ),
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => true,
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => null,
        'supports'           => array('title','editor', 'thumbnail','excerpt')
    ) );
}

Проверяем появился ли новый тип записей в админке. Добавляем произвольное поле для id галереи. Мы позже будем его использовать в JS.

add_action('add_meta_boxes_fgb_fs_gallery', 'fgb_fs_gallery_add_custom_box_id');
function fgb_fs_gallery_add_custom_box_id(){
    add_meta_box( 'x_id', __('ID', 'fgb'), 'fgb_fs_gallery_id_callback', 'fgb_fs_gallery' );
}
// HTML код блока
function fgb_fs_gallery_id_callback( $post, $meta ){
    $screens = $meta['args'];
    // Используем nonce для верификации
    wp_nonce_field( plugin_basename(__FILE__), 'x_id_noncename' );
    // Поля формы для введения данных
    echo '<label for="x_id">' . __("Put gallery id", 'fgb' ) . '</label> ';
    echo '<input type="text" id= "x_id" name="x_id" size="2"  value="'. get_post_meta( $post->ID, '_x_id',true ) .'"/>';
}
// Сохраняем данные, когда пост сохраняется
add_action( 'save_post', 'x_id_save_postdata' );
function x_id_save_postdata( $post_id ) {
    // Убедимся что поле установлено.
    if ( ! isset( $_POST['x_id'] ) )
        return;
    // проверяем nonce нашей страницы, потому что save_post может быть вызван с другого места.
    if ( ! wp_verify_nonce( $_POST['x_id_noncename'], plugin_basename(__FILE__) ) )
        return;
    // если это авто-сохранение ничего не делаем
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
        return;
    // проверяем права юзера
    if( ! current_user_can( 'edit_post', $post_id ) )
        return;
    // Все ОК. Теперь, нужно найти и сохранить данные
    // Очищаем значение поля input.
    $my_data = sanitize_text_field( $_POST['x_id'] );
    // Обновляем данные в базе данных.
    update_post_meta( $post_id, '_x_id', $my_data );
}

Шаг 2. Выводим в цикле записи на странице.

Для вывода на странице нужно вызвать событие и повесить на него хук. На странице, на которой выкладываем, пишем do_action(‘x_gallery’); а в нашем php файле продолжаем.

add_action('x_gallery', 'x_gallery');
function x_gallery(){

$argm = [
        'post_type'=>'fgb_fs_gallery',
        'orderby'=>'date',
        'order'=>'ASC'
    ];
    $query = new WP_query($argm);
    // Сюда в цикле собираем данные о картинках прикреплённых к записям
    $arr_x = [];
    $home_url = get_home_url();

    while ( $query->have_posts() ) : $query->the_post();

        $postID = get_the_ID();

        // Для фансибокса
        $needPostMetaValue = get_post_meta($postID, '_x_id', true);
        // Кладём в ассоциативный массив данные о картинках
        $arr_x[$needPostMetaValue] = get_post_images();

    ?>
        <!-- Вёрстка блока который мы выведем -->
        <!-- data-x-fancy селектор для fancybox -->
        <div>
            <a data-x-fancy="<?php echo $needPostMetaValue; ?>" data-src="<?php echo get_the_post_thumbnail_url($postID, 'full');?>" href="javascript:;">
                <?php echo get_the_post_thumbnail($postID, 'x_face', ['class'=>'w-100']);?>
            </a>
        </div>

    <?php
    endwhile;
    // Сюда получаем будем собирать ссылки на картинки
    $images = [];

    foreach ($arr_x as $gallery=>$arr){
        foreach ($arr as $item){
            $el = wp_get_attachment_image_src( $item['id'], 'full');
            $images[$gallery][] = $el[0];
        }
    }

       ?>
       <!-- Печатаем скрипт с вызовам js части -->
    <script>
        window.addEventListener('load', function () {



        <?php foreach ($images as $key=>$value): ?>

        var <?php echo $key; ?> = new XSLICK({
            galleryId: '<?php echo $key; ?>',
            images: [
                <?php foreach ($value as $item): ?>
                    <?php echo '"' . $item . '",' . PHP_EOL ?>
                <?php endforeach; ?>
            ]
        }, $);

        <?php endforeach; ?>
        });
    </script>

    <?php

}

Шаг 3. JS

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

var new3 = new XSLICK({
    galleryId: 'new3',
    images: [
            "https://xakplant.ru/wp-content/uploads/2018/11/1.jpg",
            "https://xakplant.ru/wp-content/uploads/2018/11/2.jpg",
            "https://xakplant.ru/wp-content/uploads/2018/11/3.jpg",
            "https://xakplant.ru/wp-content/uploads/2018/11/4.jpg",
        ],
}, $);

Это вызов моего js, который создаёт галерею во время загрузки страницы. В конструктор передан объект с моими данными и объект jquery. В объекте есть id галерея и массив с адресами всех картинок. Собственно к делу. В app.js пишем

var XSLICK = function (object, $) {
    this.galleryId = object.galleryId;
    this.images = object.images;
    // Создаём элементы галереи
    this.createGallery();
    // Вставляем их на страницу
    this.appendeElement();
    // Вызываем для них fancybox
    this.call($);
};
XSLICK.prototype.createGallery = function () {
    // Создаём блок в котором будут все элементы
    var gallery = document.createElement('div');
    gallery.id = this.galleryId;

    this.images.map(function (img) {
        // В цикле создаём ссылку, внутри которой картинка
        var el = new Image();
        el.src = img;
        var link = document.createElement('a');
        link.setAttribute('href', img);
        // Ссылке даём атрибут data-x-fancy c id галереи
        link.setAttribute('data-x-fancy', gallery.id);
        // Прячем
        link.style.display = 'none';
        // Вставляем всё в наш блок
        gallery.insertAdjacentElement('beforeend', link);
        link.insertAdjacentElement('beforeend', el);
    });
    this.gallery = gallery;

    return this;
};
XSLICK.prototype.appendeElement = function () {
    // Вставляем всю галерею в body
    document.body.insertAdjacentElement('beforeend', this.gallery);
};
XSLICK.prototype.call = function ($) {
    // Вызываем fancybox
    $().fancybox({selector : '[data-x-fancy="'+this.galleryId+'"]'});
}

Нужно заметить, что в fancybox3 распределении галерей несколько иначе, чем в версии 2.x и теперь инициализация разных галерей делается с помощью javascript.

$().fancybox({
    selector : 'селектор'
});

И теперь данный вызов будет следить за появлением новых элементов галереи. Это очень удобно. Но в документацию fancybox пришлось вчитываться)

Финиш

Все готово! Можете пользоваться. В итоге у вас получиться примерно это: