# Gallery3x

Компонент для MODX3  
Купить и скачать можно тут: [https://gallery3x.ru/](https://gallery3x.ru/)  
  
Демо сайт [https://demog3x.ivan345.com/](https://demog3x.ivan345.com/)

# Описание

**Gallery3x** — это современный компонент галереи изображений, разработанный **эксклюзивно для MODX3**. Он служит мощной и удобной альтернативой популярным решениям, которые не были обновлены для последней версии CMS.

Многие разработчики знают и любят отличный компонент **ms2Gallery**, который долгие годы был стандартом для создания галерей. Однако, он был создан для MODX2 и не имеет официальной поддержки в MODX3.

**Gallery3x** призван занять эту нишу, предлагая схожий богатый функционал, но на совершенно новой, современной технологической базе, полностью совместимой с MODX3.

[![g3x.gif](https://docs.ivan345.com/uploads/images/gallery/2025-07/2N0jpXB8xokFdMQI-g3x.gif)](https://docs.ivan345.com/uploads/images/gallery/2025-07/2N0jpXB8xokFdMQI-g3x.gif)

**Основные преимущества**

- **Только для MODX3:** Компонент использует все новые возможности и архитектуру третьей версии MODX.
- **Высокая производительность:** Вся обработка изображений и создание превью происходят **один раз в админ-панели** при загрузке файла. На сайте выводятся уже готовые картинки, что гарантирует максимальную скорость загрузки страниц.
- **Современные технологии:** Для обработки изображений используется передовая серверная библиотека **Glide**, обеспечивающая высокое качество и скорость генерации превью.

<div align="center" class="MsoNormal" id="bkmrk-" style="text-align: center;">---

</div>**Возможности в админ-панели (на странице ресурса)**

Интерфейс галереи интегрируется в виде отдельной вкладки "Галерея <span lang="EN-US" style="mso-ansi-language: EN-US;">G</span>3" на странице редактирования ресурса и включает в себя:

- **Современный загрузчик:**
- Загрузка файлов простым перетаскиванием (Drag-n-Drop).
- Поддержка множественной загрузки файлов.

- **Автоматическая генерация превью:**
- При загрузке автоматически создаются миниатюры (small, medium и любые другие) согласно настройкам, указанным в специальном Источнике файлов "Gallery3x Source".

- **Удобное управление:**
- Все изображения ресурса отображаются в виде наглядной сетки превью.
- **Пагинация** для галерей с большим количеством изображений.
- **Сортировка** простым перетаскиванием миниатюр.
- **Множественное выделение** файлов с помощью Ctrl + Click для групповых операций.

- **Контекстное меню (правый клик по миниатюре):**
- **Изменить свойства:** Открывает удобное окно для редактирования полей Название (title), Альтернативный текст (alt) и Описание.
- **Включить/Выключить:** Позволяет временно скрывать изображения из вывода на сайте.
- **Перегенерировать превью:** Обновляет миниатюры для одного или нескольких выделенных файлов.
- **Удалить файл(ы):** Полностью удаляет запись из базы данных и все физические файлы с сервера.


<div align="center" class="MsoNormal" id="bkmrk--1" style="text-align: center;">---

</div>**Возможности на сайте (сниппет \[\[!Gallery3x\]\])**

Компонент предоставляет один мощный и универсальный сниппет Gallery3x для вывода **уже подготовленных изображений** на сайте.

- **Универсальный вывод данных:** Сниппет не привязан к конкретной библиотеке или HTML-верстке. Он готовит массив данных для каждого изображения, включая:
- Все поля из базы данных (name, alt, description и т.д.).
- URL к оригинальному файлу (\[\[+original\_url\]\]).
- URL ко **всем** заранее сгенерированным превью <span lang="EN-US" style="mso-ansi-language: EN-US;">(\[\[+small\_url\]\], \[\[+medium\_url\]\] </span>и<span style="mso-ansi-language: EN-US;"> </span>т<span lang="EN-US" style="mso-ansi-language: EN-US;">.</span>д<span lang="EN-US" style="mso-ansi-language: EN-US;">.).</span>

- **Встроенная логика:**
- Фильтрация по текущему ресурсу.
- Вывод только **активных** файлов.
- Вывод в порядке, заданном **ручной сортировкой**.
- Опция &amp;debug=1`` для быстрой отладки.


<div align="center" class="MsoNormal" id="bkmrk--2" style="text-align: center;">---

</div>**Установка и настройка**

- Автоматическая инсталляция: При установке компонент автоматически создает таблицу в базе, Источник файлов "Gallery3x Source" и необходимые системные настройки.
- Динамическая привязка: Резолвер автоматически прописывает ID созданного Источника файлов в системную настройку gallery3x.source\_id.
- Глобальная обработка изображений: Все параметры обработки настраиваются централизованно в системных настройках, что позволяет применять их ко всем загружаемым изображениям.
- Настройка превью: Размеры миниатюр (w, h, fit и т.д.) задаются в свойствах Источника файлов в простом JSON-формате.
- Формат по умолчанию: Возможность автоматически конвертировать все превью в современные форматы, такие как WebP или AVIF.
- Фильтры и эффекты: Применение различных фильтров (например, greyscale, blur, pixelate) ко всем превью через строку параметров.
- Водяной знак: Автоматическое наложение водяного знака на все генерируемые изображения с гибкой настройкой его положения и отступов.

# Быстрый старт

Это руководство поможет вам установить, настроить и вывести вашу первую галерею с помощью компонента **Gallery3x** за несколько простых шагов.

### Шаг 1: Установка компонента

<div _ngcontent-ng-c1301062072="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk-%D0%A1%D0%BA%D0%B0%D1%87%D0%B0%D0%B9%D1%82%D0%B5-%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D1%8E%D1%8E-%D0%B2"><div _ngcontent-ng-c1957450547=""><div _ngcontent-ng-c1220367319="" class="response-container ng-tns-c1220367319-159 response-container-with-gpi ng-star-inserted" jslog="173900;track:impression"><div _ngcontent-ng-c1220367319="" class="presented-response-container ng-tns-c1220367319-159"><div _ngcontent-ng-c1220367319="" class="response-container-content ng-tns-c1220367319-159 has-thoughts"><div _ngcontent-ng-c1957450547="" class="response-content ng-tns-c1220367319-159"><div _ngcontent-ng-c3139839553="" class="markdown markdown-main-panel stronger enable-updated-hr-color" dir="ltr" style="--animation-duration: 400ms; --fade-animation-function: linear;">1. Скачайте последнюю версию транспортного пакета `Gallery3x`.
2. Перейдите в раздел **Установщик** в админ-панели MODX.
3. Загрузите и установите скачанный пакет.

</div></div></div></div></div></div></div>При установке компонент автоматически создаст все необходимые элементы: таблицы в базе данных, системные настройки, плагины и специальный **Источник файлов "Gallery3x Source"**.  
  
**Обязательно должен быть установлен pdoTools**

### Шаг 2: Настройка

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

<div _ngcontent-ng-c1301062072="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk-%D0%9F%D0%B5%D1%80%D0%B5%D0%B9%D0%B4%D0%B8%D1%82%D0%B5-%D0%B2-%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA"><div _ngcontent-ng-c1957450547=""><div _ngcontent-ng-c1220367319="" class="response-container ng-tns-c1220367319-159 response-container-with-gpi ng-star-inserted" jslog="173900;track:impression"><div _ngcontent-ng-c1220367319="" class="presented-response-container ng-tns-c1220367319-159"><div _ngcontent-ng-c1220367319="" class="response-container-content ng-tns-c1220367319-159 has-thoughts"><div _ngcontent-ng-c1957450547="" class="response-content ng-tns-c1220367319-159"><div _ngcontent-ng-c3139839553="" class="markdown markdown-main-panel stronger enable-updated-hr-color" dir="ltr" style="--animation-duration: 400ms; --fade-animation-function: linear;">1. Перейдите в **Настройки → Системные настройки**.
2. В выпадающем списке "Пространство имен" выберите **gallery3x**.
3. Найдите настройку **`gallery3x.templates`**.
4. Впишите в неё через запятую **ID шаблонов**, на страницах с которыми вы планируете использовать галерею. Например: `1, 3, 5`.

</div></div></div></div></div></div></div>> **Важно:** Если это поле останется пустым, вкладка "Галерея" не появится на страницах ресурсов.

### Шаг 3: Загрузка изображений

<div _ngcontent-ng-c1301062072="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk-%D0%9E%D1%82%D0%BA%D1%80%D0%BE%D0%B9%D1%82%D0%B5-%D0%BD%D0%B0-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80"><div _ngcontent-ng-c1957450547=""><div _ngcontent-ng-c1220367319="" class="response-container ng-tns-c1220367319-159 response-container-with-gpi ng-star-inserted" jslog="173900;track:impression"><div _ngcontent-ng-c1220367319="" class="presented-response-container ng-tns-c1220367319-159"><div _ngcontent-ng-c1220367319="" class="response-container-content ng-tns-c1220367319-159 has-thoughts"><div _ngcontent-ng-c1957450547="" class="response-content ng-tns-c1220367319-159"><div _ngcontent-ng-c3139839553="" class="markdown markdown-main-panel stronger enable-updated-hr-color" dir="ltr" style="--animation-duration: 400ms; --fade-animation-function: linear;">1. Откройте на редактирование любой ресурс, использующий один из шаблонов, указанных на предыдущем шаге.
2. Вы должны увидеть новую вкладку **"Галерея"**.
3. Перейдите на неё и просто **перетащите несколько изображений** в область "Drop files here to upload".
4. После загрузки вы сразу увидите сгенерированные миниатюры. Вы можете перетаскивать их, чтобы изменить порядок сортировки.

</div></div></div></div></div></div></div>### Шаг 4: Вывод галереи на сайте

Теперь выведем загруженные изображения на страницу.

> #### Кастомизация чанков
> 
> Для изменения внешнего вида галереи рекомендуется **не редактировать** стандартные чанки компонента (`tpl.Gallery3x...`) напрямую. При обновлении `Gallery3x` все ваши изменения в этих файлах могут быть **перезаписаны**.
> 
> Самый правильный способ — **создать копию** стандартного чанка, дать ей уникальное имя (например, `tpl.mysite.gallery.item`) и уже в ней производить все необходимые изменения. Затем просто укажите имя вашего нового чанка в вызове сниппета.

**Подключите библиотеки** В шаблоне вашей страницы подключите стили и скрипты для галереи fancybox

1. <div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-118 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_f82dbb5d36fa6cd5","c_b8511ae2af5280fd",null,"rc_207c98c2c8980344",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="code-block-decoration header-formatted gds-title-s ng-tns-c1906655948-118 ng-star-inserted"><span class="ng-tns-c1906655948-118"> Пример карусели</span><div _ngcontent-ng-c1906655948="" class="buttons ng-tns-c1906655948-118 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c1906655948-118 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-118"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-118">  
    </div></div></div>```
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.css" />
    
    [[!Gallery3x?
        &tplOuter=`tpl.Gallery3x.Fancybox.outer`
        &tplThumb=`tpl.Gallery3x.Fancybox.thumbItem`
    ]]
    
    <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.umd.js"></script>
    <script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function() {
        const mainContainer = document.getElementById('fancybox-main-[[*id]]');
        const thumbsContainer = document.getElementById('fancybox-thumbs-[[*id]]');
        if (!mainContainer || !thumbsContainer) return;
    
        const thumbLinks = thumbsContainer.querySelectorAll('.thumb-item');
    
        // Инициализируем Fancybox на всех превью
        Fancybox.bind('[data-fancybox="gallery-[[*id]]"]', {
            // Ваши настройки Fancybox, если нужны
        });
    
        // Обрабатываем клики по превью для смены главного изображения
        thumbsContainer.addEventListener('click', function(e) {
            e.preventDefault();
            const target = e.target.closest('.thumb-item');
            if (!target) return;
    
            const mainImage = mainContainer.querySelector('img');
            const mainLink = mainContainer.querySelector('a');
            mainImage.src = target.dataset.mediumUrl;
            mainLink.href = target.href;
            mainLink.setAttribute('data-caption', target.getAttribute('data-caption'));
    
            thumbLinks.forEach(link => link.classList.remove('is-active'));
            target.classList.add('is-active');
        });
    
        // Делаем первое превью активным
        if (thumbLinks.length > 0) {
            thumbLinks[0].classList.add('is-active');
        }
    });
    </script>
    
    ```
    
    <div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-118 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_f82dbb5d36fa6cd5","c_b8511ae2af5280fd",null,"rc_207c98c2c8980344",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-118"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-118"></div></div></div>Пример карусели с феном  
      
    ```
    
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.css" />
    
    <style>
    .fancybox-carousel-container { max-width: 800px; margin: 40px auto; }
    .fancybox-carousel-main { margin-bottom: 15px; border-radius: 5px; overflow: hidden; box-shadow: 0 5px 15px rgba(0,0,0,0.1); }
    .fancybox-carousel-main img { width: 100%; height: auto; display: block; cursor: pointer; }
    .fancybox-carousel-thumbs { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 10px; }
    .fancybox-carousel-thumbs .thumb-item { display: block; border: 2px solid transparent; border-radius: 4px; overflow: hidden; transition: border-color 0.2s ease; flex-shrink: 0; }
    .fancybox-carousel-thumbs .thumb-item:hover, .fancybox-carousel-thumbs .thumb-item.is-active { border-color: #007bff; }
    .fancybox-carousel-thumbs .thumb-item img { width: 100px; height: 75px; display: block; object-fit: cover; }
    </style>
    
    [[!Gallery3x?
        &fenom=`1`
        &tplOuter=`tpl.Gallery3x.Fancybox.Carousel.fenom`
    ]]
    
    <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.umd.js"></script>
    <script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function() {
        const mainContainer = document.getElementById('fancybox-main-[[*id]]');
        const thumbsContainer = document.getElementById('fancybox-thumbs-[[*id]]');
        if (!mainContainer || !thumbsContainer) return;
    
        const thumbLinks = thumbsContainer.querySelectorAll('.thumb-item');
    
        // Инициализируем Fancybox на всех превью
        Fancybox.bind('[data-fancybox="gallery-[[*id]]"]', {
            // настройки Fancybox, если нужны
        });
    
        // Обрабатываем клики по превью для смены главного изображения
        thumbsContainer.addEventListener('click', function(e) {
            e.preventDefault();
            const target = e.target.closest('.thumb-item');
            if (!target) return;
    
            const mainImage = mainContainer.querySelector('img');
            const mainLink = mainContainer.querySelector('a');
            mainImage.src = target.dataset.mediumUrl;
            mainLink.href = target.href;
            mainLink.setAttribute('data-caption', target.getAttribute('data-caption'));
    
            thumbLinks.forEach(link => link.classList.remove('is-active'));
            target.classList.add('is-active');
        });
    
        // Делаем первое превью активным
        if (thumbLinks.length > 0) {
            thumbLinks[0].classList.add('is-active');
        }
    });
    </script>
    ```

 Пример "Ленты с превью"

```
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.css"/>
          


[[!Gallery3x?
    &tplOuter=`tpl.Gallery3x.Fancybox.GridOuter`
    &tplThumb=`tpl.Gallery3x.Fancybox.GridItem`
]]



<script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.umd.js"></script>
<script>
  Fancybox.bind('[data-fancybox="gallery"]', {
    //
  });    
</script>
    
```

Пример "Ленты с превью" с fenom

```
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.css"/>
          


[[!Gallery3x?
    &tplOuter=`tpl.Gallery3x.Fancybox.GridOuter.fenom`
    &fenom=`1`
]]


<script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.umd.js"></script>

<script>
  Fancybox.bind('[data-fancybox="gallery-[[*id]]"]', {
    //
  });    
</script>
```

<div _ngcontent-ng-c2485367380="" class="code-block ng-tns-c2485367380-166 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--2" jslog="223238;track:impression;BardVeMetadataKey:[["r_c77ac8e1760b9a4d","c_b8511ae2af5280fd",null,"rc_566d22cdbec1574e",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2485367380="" class="formatted-code-block-internal-container ng-tns-c2485367380-166"><div _ngcontent-ng-c2485367380="" class="animated-opacity ng-tns-c2485367380-166"></div></div></div><div _ngcontent-ng-c1301062072="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk-%D0%92%D1%81%D1%82%D0%B0%D0%B2%D1%8C%D1%82%D0%B5-%D0%BA%D0%BE%D0%B4-%D0%BD%D0%B0-%D1%81%D1%82%D1%80%D0%B0"><div _ngcontent-ng-c1957450547=""><div _ngcontent-ng-c1220367319="" class="response-container ng-tns-c1220367319-159 response-container-with-gpi ng-star-inserted" jslog="173900;track:impression"><div _ngcontent-ng-c1220367319="" class="presented-response-container ng-tns-c1220367319-159"><div _ngcontent-ng-c1220367319="" class="response-container-content ng-tns-c1220367319-159 has-thoughts"><div _ngcontent-ng-c1957450547="" class="response-content ng-tns-c1220367319-159"><div _ngcontent-ng-c3139839553="" class="markdown markdown-main-panel stronger enable-updated-hr-color" dir="ltr" id="bkmrk-%D0%92%D1%81%D1%82%D0%B0%D0%B2%D1%8C%D1%82%D0%B5-%D0%BA%D0%BE%D0%B4-%D0%BD%D0%B0-%D1%81%D1%82%D1%80%D0%B0-1" style="--animation-duration: 400ms; --fade-animation-function: linear;"></div><div _ngcontent-ng-c1957450547="" class="response-footer gap has-thoughts complete"></div></div></div></div></div></div></div>

# Настройки компонента

Все настройки компонента `Gallery3x` находятся в админ-панели MODX в разделе **Настройки → Системные настройки**. В выпадающем списке "Пространство имен" выберите `gallery3x`, чтобы увидеть все доступные опции.

Настройки разделены на логические группы для удобства управления.

### Основные настройки

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

<table class="table table-bordered table-striped" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD"><thead><tr><th style="width: 25%;">Ключ</th><th style="width: 20%;">Название</th><th>Описание</th></tr></thead><tbody><tr><td>**gallery3x.source\_id**</td><td>Источник файлов</td><td>Укажите ID источника файлов (Media Source), где будут храниться изображения. Обычно компонент создает свой источник при установке и прописывает его ID автоматически.</td></tr><tr><td>**gallery3x.driver**</td><td>Драйвер обработки</td><td>Библиотека для обработки изображений на сервере.   
Варианты: `imagick` (рекомендуется) или `gd`.</td></tr><tr><td>**gallery3x.templates**</td><td>Активные шаблоны</td><td>Список ID шаблонов через запятую (например: `1, 3, 5`). Вкладка "Галерея" появится только у ресурсов с этими шаблонами. Если пусто — вкладка скрыта.</td></tr><tr><td>**gallery3x.format**</td><td>Формат конвертации</td><td>Формат, в который будут автоматически конвертироваться все загружаемые изображения. По умолчанию: `webp`.</td></tr><tr><td>**gallery3x.filters**</td><td>Глобальные фильтры</td><td>Строка фильтров phpThumb, применяемая ко всем изображениям.   
Пример: `greyscale` (ч/б) или `blur=5`.</td></tr><tr><td>**gallery3x.watermark\_path**</td><td>Путь к водяному знаку</td><td>Путь к файлу картинки от корня сайта. Оставьте пустым, чтобы отключить водяной знак.  
Пример: `assets/images/logo.png`.</td></tr><tr><td>**gallery3x.watermark\_position**</td><td>Позиция водяного знака</td><td>Расположение водяного знака на изображении.   
Варианты: `top-left`, `top-center`, `top-right`, `center`, `bottom-left`, `bottom-center`, `bottom-right`.</td></tr><tr><td>**gallery3x.watermark\_padding**</td><td>Отступ водяного знака</td><td>Отступ от края изображения в пикселях. По умолчанию: `10`.</td></tr><tr><td>**gallery3x.ignore\_template\_source**</td><td>Игнорировать источник шаблона</td><td>Если `Да`, галерея всегда использует источник из настройки `gallery3x.source_id`, игнорируя настройки медиа-источников, привязанные к TV или контексту.</td></tr><tr><td>**gallery3x.new\_file\_position**</td><td>Позиция новых файлов</td><td>Определяет, куда добавляются свежезагруженные файлы.  
`end` — в конец списка,  
`start` — в начало списка.</td></tr><tr><td>**gallery3x.per\_page**</td><td>Элементов на странице</td><td>Количество изображений, отображаемых на одной странице в админ-панели (пагинация). По умолчанию: `30`.</td></tr><tr><td>**gallery3x.collections\_thumb\_size**</td><td>Размер превью в Collections</td><td>Размер миниатюры при просмотре через компонент Collections.  
Варианты: `small`, `medium`, `large`.</td></tr><tr><td>**gallery3x.video\_enable**</td><td>Включить видео</td><td>Активирует вкладку "Видеогалерея" для добавления ссылок с YouTube, VK, Rutube.</td></tr><tr><td>**gallery3x.groups\_per\_user**</td><td>Изоляция групп</td><td>Если `Да`, каждый менеджер видит и управляет только теми группами (тегами), которые создал сам. Если `Нет` — группы общие.</td></tr></tbody></table>

<div class="horizontal-scroll-wrapper" id="bkmrk-"><div class="table-block-component"><div _ngcontent-ng-c1702402772="" class="table-block has-export-button"><div _ngcontent-ng-c1702402772="" class="table-content not-end-of-paragraph" not-end-of-paragraph="">  
</div><div _ngcontent-ng-c1702402772="" class="table-footer hide-from-message-actions ng-star-inserted" hide-from-message-actions="">  
</div></div></div></div>### Генерация превью

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

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-1"><div class="table-block-component"><div _ngcontent-ng-c1702402772="" class="table-block has-export-button"><div _ngcontent-ng-c1702402772="" class="table-content not-end-of-paragraph" not-end-of-paragraph=""><table><thead><tr><td>Ключ</td><td>Название</td><td>Описание</td></tr></thead><tbody><tr><td>**gallery3x.format**</td><td>Формат превью</td><td>Укажите формат, в который будут конвертироваться все превью (например, `webp`, `avif`, `jpg`). Оставьте пустым, чтобы сохранить оригинальный формат файла.</td></tr><tr><td>**gallery3x.filters**</td><td>Фильтры изображений</td><td>Позволяет применить один или несколько фильтров к превью. Фильтры перечисляются через | (Вертикальная черта)</td></tr><tr><td>**gallery3x.watermark\_path**</td><td>Путь к водяному знаку</td><td>Путь к файлу водяного знака от корня сайта. **Пример:** `assets/images/watermark.png`. Оставьте пустым, чтобы отключить.</td></tr><tr><td>**gallery3x.watermark\_position**</td><td>Позиция водяного знака</td><td>Расположение водяного знака. Возможные значения: `top-left`, `top`, `top-right`, `left`, `center`, `right`, `bottom-left`, `bottom`, `bottom-right`.</td></tr><tr><td>**gallery3x.watermark\_padding**</td><td>Отступ водяного знака</td><td>Отступ водяного знака от краев изображения в пикселях.</td></tr></tbody></table>

</div></div></div></div>
### Плейсхолдеры изображений

Эта группа настроек управляет функцией автоматического вывода плейсхолдеров изображений на страницах сайта (аналог функции из `ms2Gallery`).

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-2"><div class="table-block-component"><div _ngcontent-ng-c1702402772="" class="table-block has-export-button"><div _ngcontent-ng-c1702402772="" class="table-content not-end-of-paragraph" not-end-of-paragraph=""><table><thead><tr><td>Ключ</td><td>Название</td><td>Описание</td></tr></thead><tbody><tr><td>**gallery3x.set\_placeholders**</td><td>Включить плейсхолдеры на сайте</td><td>Главный переключатель. Установите в "Да", чтобы плагин начал создавать плейсхолдеры `[[+g3x.0]]`, `[[+g3x.1.url]]` и т.д. **Включайте, только если это действительно нужно.**</td></tr><tr><td>**gallery3x.placeholders\_tpl**</td><td>Чанк для плейсхолдеров</td><td>Имя чанка для оформления плейсхолдера `[[+g3x.N]]`. Если пусто, будет выведен массив данных. Поддерживается Fenom.</td></tr><tr><td>**gallery3x.placeholders\_for\_templates**</td><td>Включить для шаблонов</td><td>Список ID шаблонов через запятую, для которых будет работать эта функция. Если пусто — работает для всех.</td></tr><tr><td>**gallery3x.placeholders\_thumbs**</td><td>Размеры превью для плейсхолдеров</td><td>Список размеров превью через запятую, которые нужно выбирать (например, `small,medium`). Это экономит ресурсы.</td></tr></tbody></table>

</div></div></div></div>
### Настройки имен файлов

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

<div class="horizontal-scroll-wrapper" id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD-3"><div class="table-block-component"><div _ngcontent-ng-c1702402772="" class="table-block has-export-button"><div _ngcontent-ng-c1702402772="" class="table-content not-end-of-paragraph" not-end-of-paragraph=""><table><thead><tr><td>Ключ</td><td>Название</td><td>Описание</td></tr></thead><tbody><tr><td>**gallery3x.filename\_as\_hash**</td><td>Использовать хеш в качестве имени файла</td><td>Если "Да", имя файла будет заменено на его MD5-хеш (например, `a1b2c3d4...jpg`). Гарантирует уникальность, но делает имена нечитаемыми. Имеет наивысший приоритет.</td></tr><tr><td>**gallery3x.filename\_translit**</td><td>Транслитерировать имена файлов</td><td>Если "Да", кириллические символы будут заменены на латиницу. **Пример:** `Фото.jpg` → `foto.jpg`.</td></tr><tr><td>**gallery3x.filename\_sanitize**</td><td>Очищать имена файлов от спецсимволов</td><td>Если "Да", все спецсимволы (кроме букв, цифр, `-` и `_`) будут удалены. Пробелы заменяются на дефис. **Пример:** `мой файл (1)!.jpg` → `moy-fayl-1.jpg`.</td></tr><tr><td>**gallery3x.filename\_lowercase**</td><td>Приводить имена файлов к нижнему регистру</td><td>Если "Да", все имена и расширения будут преобразованы в нижний регистр. **Пример:** `MyPhoto.JPG` → `myphoto.jpg`.</td></tr></tbody></table>

</div></div></div></div>### Контроль доступа

У администраторов должны быть права на создание и сохранение (ну или "неограниченные права у администратора")  
  
[![Screenshot_2.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-11/scaled-1680-/eqwjZsk4OjLjdNy8-screenshot-2.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-11/eqwjZsk4OjLjdNy8-screenshot-2.jpg)

# Генерация превью

`Gallery3x` использует продвинутый подход к обработке изображений, который обеспечивает высокую производительность сайта и отличное качество миниатюр.

### Преимущество генерации в админ-панели

Ключевой особенностью компонента является то, что вся "тяжелая" работа по обработке изображений (изменение размера, нарезка, наложение фильтров и водяных знаков) происходит **только один раз — в момент загрузки файла в админ-панели**.

Это дает огромное преимущество в производительности:

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

Для всех операций с изображениями используется **продвинутая PHP библиотека Glide**. Она обеспечивает высокое качество обработки, поддерживает современные форматы и предоставляет широкий набор инструментов для манипуляций с изображениями.

---

## Настройка генерации

Настройка разделена на две части:

1. **Основные параметры (размеры)** — задаются в Источнике файлов.
2. **Глобальные эффекты (фильтры, водяной знак)** — задаются в Системных настройках.

### Основные параметры (в Источнике файлов)

Все размеры превью, которые должен создавать компонент, настраиваются в вашем Источнике файлов "Gallery3x Source".

1. Перейдите в **Медиа → Источники файлов**.
2. Откройте **"Gallery3x Source"**.
3. Перейдите на вкладку **"Свойства источника файлов"**.
4. Найдите параметр **`gallery3x_thumbnails`**.

Этот параметр принимает JSON-строку, которая описывает каждый необходимый размер превью.

**Пример JSON:**

<div _ngcontent-ng-c2485367380="" class="code-block ng-tns-c2485367380-140 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-json" jslog="223238;track:impression;BardVeMetadataKey:[["r_3d1ff3f9dca7451b","c_b8511ae2af5280fd",null,"rc_b74431b25722d597",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2485367380="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2485367380-140 ng-star-inserted"><span class="ng-tns-c2485367380-140">JSON</span><div _ngcontent-ng-c2485367380="" class="buttons ng-tns-c2485367380-140 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2485367380-140 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2485367380="" class="formatted-code-block-internal-container ng-tns-c2485367380-140"><div _ngcontent-ng-c2485367380="" class="animated-opacity ng-tns-c2485367380-140">  
</div></div></div>```
[
  {"name": "small", "w": 150, "h": 100, "fit": "crop-center", "q": 80},
  {"name": "medium", "w": 400, "h": 300, "fit": "contain"},
  {"name": "big", "w": 1200}
]

```

<div _ngcontent-ng-c2485367380="" class="code-block ng-tns-c2485367380-140 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--2" jslog="223238;track:impression;BardVeMetadataKey:[["r_3d1ff3f9dca7451b","c_b8511ae2af5280fd",null,"rc_b74431b25722d597",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2485367380="" class="formatted-code-block-internal-container ng-tns-c2485367380-140"><div _ngcontent-ng-c2485367380="" class="animated-opacity ng-tns-c2485367380-140"></div></div></div>#### Параметры расшифровываются так:

- **`name`**: (Обязательно) Уникальное имя размера. Будет использоваться для плейсхолдеров, например, `[[+small]]`.
- **`w`**: Ширина изображения в пикселях.
- **`h`**: Высота изображения в пикселях.
- **`fit`**: (Очень важный параметр) Метод вписывания изображения в заданные размеры.
    
    
    - `contain`: Вписывает изображение целиком, сохраняя пропорции. Поля могут остаться пустыми.
    - `max`: Уменьшает изображение, пока оно не впишется по ширине или высоте.
    - `fill`: Растягивает изображение, чтобы заполнить все пространство, сохраняя пропорции. Лишнее обрезается.
    - `stretch`: Растягивает изображение до точных размеров `w` и `h`, игнорируя пропорции.
    - `crop`: Обрезает изображение. Можно указать точку фокуса, например `crop-center` (по умолчанию), `crop-top-left` и т.д.
- **`q`**: Качество изображения в процентах (от 0 до 100). Актуально для форматов `jpg` и `webp`.
- **`fm`**: Формат файла. Например, `webp`, `avif`, `jpg`. Если не указан, используется глобальная настройка.

---

### Глобальные эффекты (в Системных настройках)

Эти настройки находятся в **Настройки → Системные настройки**, пространство имен `gallery3x`. Они применяются ко **всем** превью, которые генерирует компонент.

#### Наложение водяного знака (Watermark)

- **`gallery3x.watermark_path`** Путь к файлу водяного знака от корня сайта. Например: `assets/images/watermark.png`. Если поле пустое, водяной знак не накладывается.
- **`gallery3x.watermark_position`** Расположение водяного знака. Возможные значения: `top-left`, `top`, `top-right`, `left`, `center`, `right`, `bottom-left`, `bottom`, `bottom-right` (по умолчанию).
- **`gallery3x.watermark_padding`** Отступ водяного знака от краев изображения в пикселях.

#### Фильтры и формат

- **`gallery3x.format`** Позволяет автоматически конвертировать **все** превью в указанный формат (например, `webp`). Если оставить пустым, формат останется оригинальным.
- **`gallery3x.filters`** Строка для применения одного или нескольких фильтров ко всем превью. Фильтры перечисляются через `|`.
    
    
    - **Пример 1 (черно-белое изображение):** `greyscale`
    - **Пример 2 (размытие):** `blur=10`
    - **Пример 3 (комбинация):** `sepia|brightness=10|contrast=-5`

# Сниппеты

# Gallery3x

Компонент `Gallery3x` поставляется с основным сниппетом `[[!Gallery3x]]`, который отвечает за вывод изображений на страницах сайта. Сниппет разработан с упором на гибкость и производительность, позволяя создавать галереи любой сложности.

### Ключевая особенность

Сниппет **не создает превью "на лету"**. Он работает с уже готовыми, заранее сгенерированными изображениями, которые были созданы в админ-панели при загрузке файлов. Это обеспечивает максимальную скорость загрузки страниц для посетителей вашего сайта.

---

## Сниппет `[[!Gallery3x]]`

Основная задача сниппета — получить все активные изображения для указанного ресурса, отсортировать их и передать данные в чанки для оформления.

Документация с добавленным новым параметром.

<div class="horizontal-scroll-wrapper" id="bkmrk--2"><div class="table-block-component"><div class="horizontal-scroll-wrapper"><div class="table-block-component"><div _ngcontent-ng-c1702402772="" class="table-block has-export-button"><div _ngcontent-ng-c1702402772="" class="table-content not-end-of-paragraph" not-end-of-paragraph=""><table style="width: 100%; height: 566.4px;"><thead><tr style="height: 29.8px;"><td style="width: 15.6055%; height: 29.8px;">раметр</td><td style="width: 24.2933%; height: 29.8px;">По умолчанию</td><td style="width: 60.1668%; height: 29.8px;">Описание</td></tr></thead><tbody><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;resource**</td><td style="width: 24.2933%; height: 47.5167px;">ID текущего ресурса</td><td style="width: 60.1668%; height: 47.5167px;">ID ресурса, из которого нужно вывести изображения. Используется, если `&parents` и `&resources` не заданы.</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;parents**</td><td style="width: 24.2933%; height: 47.5167px;">`null`</td><td style="width: 60.1668%; height: 47.5167px;">Список ID родительских ресурсов через запятую. Выбирает картинки из этих ресурсов и всех их дочерних. `0` — выборка со всего сайта.</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;resources**</td><td style="width: 24.2933%; height: 47.5167px;">`null`</td><td style="width: 60.1668%; height: 47.5167px;">Список ID ресурсов через запятую. ID с минусом (-) исключает ресурс. Имеет приоритет над `&parents`, если указаны положительные ID.</td></tr><tr style="height: 30.7167px;"><td style="width: 15.6055%; height: 30.7167px;">**&amp;tplOuter**</td><td style="width: 24.2933%; height: 30.7167px;">`...`</td><td style="width: 60.1668%; height: 30.7167px;">Имя чанка-обертки для сложных галерей (например, каруселей).</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;tplThumb**</td><td style="width: 24.2933%; height: 47.5167px;">`...`</td><td style="width: 60.1668%; height: 47.5167px;">Имя чанка для элемента в ленте превью (используется вместе с `tplOuter`, **игнорируется в режиме Fenom**).</td></tr><tr style="height: 82.95px;"><td style="width: 15.6055%; height: 82.95px;">**&amp;fenom**</td><td style="width: 24.2933%; height: 82.95px;">`0`</td><td style="width: 60.1668%; height: 82.95px;">Если установить в `1` и на сайте установлен `pdoTools`, сниппет будет работать в режиме Fenom. В этом режиме он не обрабатывает чанк `&tplThumb`, а передает в чанк `&tplOuter` сырой массив со всеми данными `{$files}`, который вы можете обработать в цикле `{foreach}`.</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;limit**</td><td style="width: 24.2933%; height: 47.5167px;">0</td><td style="width: 60.1668%; height: 47.5167px;">Ограничение на количество выводимых изображений. `0` — без ограничений.</td></tr><tr style="height: 29.8px;"><td style="width: 15.6055%; height: 29.8px;">**&amp;sortby**</td><td style="width: 24.2933%; height: 29.8px;">position</td><td style="width: 60.1668%; height: 29.8px;">Поле для сортировки изображений.</td></tr><tr style="height: 29.8px;"><td style="width: 15.6055%; height: 29.8px;">**&amp;sortdir**</td><td style="width: 24.2933%; height: 29.8px;">ASC</td><td style="width: 60.1668%; height: 29.8px;">Направление сортировки (ASC или DESC).</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;showInactive**</td><td style="width: 24.2933%; height: 47.5167px;">0</td><td style="width: 60.1668%; height: 47.5167px;">Если установить в `1`, будут выводиться также и выключенные в админке изображения.</td></tr><tr style="height: 30.7167px;"><td style="width: 15.6055%; height: 30.7167px;">**&amp;where**</td><td style="width: 24.2933%; height: 30.7167px;">`''`</td><td style="width: 60.1668%; height: 30.7167px;">JSON-строка с дополнительными условиями выборки.</td></tr><tr style="height: 47.5167px;"><td style="width: 15.6055%; height: 47.5167px;">**&amp;debug**</td><td style="width: 24.2933%; height: 47.5167px;">0</td><td style="width: 60.1668%; height: 47.5167px;">Если установить в `1`, вместо галереи на странице будет выведен массив со всеми данными, которые сниппет подготовил.</td></tr><tr><td style="width: 15.6055%;">**&amp;group**</td><td style="width: 24.2933%;">  
</td><td style="width: 60.1668%;">Фильтр по группе</td></tr><tr><td style="width: 15.6055%;">**&amp;return**</td><td style="width: 24.2933%;">  
</td><td style="width: 60.1668%;">Определяет формат возвращаемых данных. (data, json, ids)</td></tr><tr><td style="width: 15.6055%;">**&amp;toPlaceholder**</td><td style="width: 24.2933%;">  
</td><td style="width: 60.1668%;">Сохраняет данные в \*\*плейсхолдер\*\* вместо вывода. Сниппет возвращает пустую строку.</td></tr></tbody></table>

</div></div></div></div></div></div>### Доступные плейсхолдеры

Сниппет передает в чанк **все поля** из таблицы компонента, а также автоматически генерирует URL для всех существующих превью.

- `[[+id]]` - ID записи
- `[[+name]]` - Название (title)
- `[[+description]]` - Описание
- `[[+alt]]` - Альтернативный текст
- `[[+file]]` - Имя файла (например, `my-photo.jpg`)
- `[[+createdon]]` - Дата загрузки
- `[[+size]]` - Размер файла в байтах
- **`[[+original_url]]`** - URL к оригинальному изображению
- **`[[+small_url]]`** - URL к превью 'small'
- **`[[+medium_url]]`** - URL к превью 'medium'
- `[[+любое_имя_превью_url]]` - Если вы создадите превью с именем `big`, здесь будет доступен плейсхолдер `[[+big_url]]`.

сниппет Gallery3x поддерживает параметры `&amp;return` и `&amp;toPlaceholder`, которые позволяют получать данные галереи в виде массива или JSON вместо готового HTML. Это особенно полезно при работе с Fenom-циклами, PdoPage с ajax-загрузкой, и для создания кастомной разметки.

# Gallery3xVideos

# Gallery3xVideos - Сниппет для вывода видео

Сниппет для вывода видеогалерей из различных сервисов: **Rutube**, **YouTube**, **VK**, **Vimeo**, **Dailymotion**, **Coub**, **OK.ru**, **Яндекс.Дзен**.

---

## Возможности

- Вывод видео из текущего или указанных ресурсов
- Поддержка 8+ видеосервисов
- Автоматическая генерация встроенных плееров (iframe)
- Фильтрация по группам
- Сортировка и пагинация
- Поддержка Fenom шаблонов
- Красивые готовые чанки с анимацией
- Адаптивный дизайн

---

## Базовое использование

### Простой вызов

```
[[Gallery3xVideos]]
```

### С Fenom (рекомендуется)

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

---

## Параметры

<table id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%A2%D0%B8%D0%BF-%D0%9F%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB"><thead><tr><th>Параметр</th><th>Тип</th><th>По умолчанию</th><th>Описание</th></tr></thead><tbody><tr><td>`tplOuter`</td><td>string</td><td>`tpl.Gallery3x.Video.outer`</td><td>Внешний чанк-обертка</td></tr><tr><td>`tplItem`</td><td>string</td><td>`tpl.Gallery3x.Video.item`</td><td>Чанк элемента (без Fenom)</td></tr><tr><td>`fenom`</td><td>bool</td><td>`0`</td><td>Использовать Fenom (1 или 0)</td></tr><tr><td>`resource`</td><td>int</td><td>текущий</td><td>ID ресурса</td></tr><tr><td>`resources`</td><td>string</td><td>-</td><td>ID ресурсов через запятую</td></tr><tr><td>`parents`</td><td>string</td><td>-</td><td>ID родителей (включая детей)</td></tr><tr><td>`limit`</td><td>int</td><td>`0`</td><td>Лимит выборки (0 = все)</td></tr><tr><td>`offset`</td><td>int</td><td>`0`</td><td>Смещение выборки</td></tr><tr><td>`group`</td><td>string</td><td>-</td><td>Фильтр по группам</td></tr><tr><td>`sortby`</td><td>string</td><td>`position`</td><td>Поле сортировки</td></tr><tr><td>`sortdir`</td><td>string</td><td>`ASC`</td><td>Направление (ASC/DESC)</td></tr><tr><td>`showInactive`</td><td>bool</td><td>`0`</td><td>Показывать неактивные</td></tr><tr><td>`debug`</td><td>bool</td><td>`0`</td><td>Режим отладки</td></tr></tbody></table>

---

## Доступные чанки

### 1. tpl.Gallery3x.Video.outer + item (БЕЗ Fenom)

Базовая сетка видео для стандартного MODX.

**Использование:**

```
[[Gallery3xVideos?
    &tplOuter=`tpl.Gallery3x.Video.outer`
    &tplItem=`tpl.Gallery3x.Video.item`
]]
```

**Особенности:**

- Адаптивная сетка карточек
- Превью с анимацией Play
- Бейджи сервисов
- Клик → переход на видео

---

### 2. tpl.Gallery3x.Video.outer.fenom (С Fenom)

Все в одном чанке с Fenom. **Рекомендуется!**

**Использование:**

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

**Особенности:**

- Все то же, что в варианте 1
- Обработка пустого состояния
- Более гибкая настройка
- Градиент для видео без превью

---

### 3. tpl.Gallery3x.Video.grid + item (компактная)

Компактная сетка для боковых панелей.

**Использование:**

```
[[Gallery3xVideos?
    &tplOuter=`tpl.Gallery3x.Video.grid`
    &tplItem=`tpl.Gallery3x.Video.grid.item`
    &limit=`6`
]]
```

**Особенности:**

- Более компактные карточки
- Упрощенная информация
- Подходит для виджетов

---

### 4. tpl.Gallery3x.Video.embedded.fenom (встроенные плееры)

Видео воспроизводятся прямо на странице через iframe.

**Использование:**

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.embedded.fenom`
]]
```

**Особенности:**

- Видео встроены на страницу
- Адаптивные iframe (16:9)
- Кнопка "Открыть на сервисе"
- Полная информация под видео

---

## Примеры использования

### Видео текущего ресурса

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

### Видео из нескольких ресурсов

```
[[Gallery3xVideos?
    &fenom=`1`
    &resources=`10,15,20`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

### Видео из группы "Промо"

```
[[Gallery3xVideos?
    &fenom=`1`
    &group=`Промо`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

### С лимитом (6 видео)

```
[[Gallery3xVideos?
    &fenom=`1`
    &limit=`6`
    &sortby=`createdon`
    &sortdir=`DESC`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

### С пагинацией (pdoPage)

```
[[pdoPage?
    &element=`Gallery3xVideos`
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
    &limit=`12`
]]

[[!+page.nav]]
```

### Встроенные видео на странице

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Video.embedded.fenom`
    &group=`Уроки`
]]
```

---

## Доступные поля в чанках

### Поля каждого видео (в tplItem или в цикле foreach)

#### БЕЗ Fenom (в tplItem):

```
[[+id]]               <!-- ID видео в БД -->
[[+resource_id]]      <!-- ID ресурса MODX -->
[[+url]]              <!-- Полная ссылка на видео -->
[[+title]]            <!-- Название видео -->
[[+description]]      <!-- Описание видео -->
[[+thumbnail]]        <!-- Путь к превью (относительный) -->
[[+thumbnail_url]]    <!-- Полный URL превью -->
[[+service]]          <!-- Сервис: youtube, rutube, vk, vimeo, dailymotion, coub, ok, dzen -->
[[+video_id]]         <!-- ID видео на сервисе -->
[[+group]]            <!-- Группа (или группы через ||) -->
[[+position]]         <!-- Позиция сортировки -->
[[+active]]           <!-- Активность: 1 (да) или 0 (нет) -->
[[+special]]          <!-- Особое: 1 (да) или 0 (нет) -->
[[+createdon]]        <!-- Дата создания -->
[[+createdby]]        <!-- ID создателя -->
[[+updatedon]]        <!-- Дата обновления -->
[[+updatedby]]        <!-- ID обновившего -->
[[+embed_html]]       <!-- HTML-код iframe плеера -->
```

#### С Fenom (в цикле foreach):

```
{$video.id}               {* ID видео в БД *}
{$video.resource_id}      {* ID ресурса MODX *}
{$video.url}              {* Полная ссылка на видео *}
{$video.title}            {* Название видео *}
{$video.description}      {* Описание видео *}
{$video.thumbnail}        {* Путь к превью (относительный) *}
{$video.thumbnail_url}    {* Полный URL превью *}
{$video.service}          {* Сервис: youtube, rutube, vk... *}
{$video.video_id}         {* ID видео на сервисе *}
{$video.group}            {* Группа (или группы через ||) *}
{$video.position}         {* Позиция сортировки *}
{$video.active}           {* Активность: 1 или 0 *}
{$video.special}          {* Особое: 1 или 0 *}
{$video.createdon}        {* Дата создания *}
{$video.createdby}        {* ID создателя *}
{$video.updatedon}        {* Дата обновления *}
{$video.updatedby}        {* ID обновившего *}
{$video.embed_html | unescape}  {* HTML-код iframe плеера *}
```

---

### Дополнительные поля в tplOuter

В чанке `tplOuter` доступны следующие плейсхолдеры:

#### БЕЗ Fenom:

```
[[+items]]            <!-- Все видео, отрендеренные через tplItem -->
[[+total]]            <!-- Общее количество видео -->
[[+first.id]]         <!-- ID первого видео -->
[[+first.title]]      <!-- Название первого видео -->
[[+first.*]]          <!-- Любое поле первого видео (см. выше) -->
```

#### С Fenom:

```
{$videos}             {* Массив всех видео для foreach *}
{$total}              {* Общее количество видео *}
{$first.id}           {* ID первого видео *}
{$first.title}        {* Название первого видео *}
{$first.*}            {* Любое поле первого видео *}
```

**Пример использования в tplOuter:**

```
<div class="video-gallery">
    <p>Найдено видео: [[+total]]</p>
    
    [[+items]]  <!-- Здесь выводятся все видео -->
</div>
```

---

## Реальные примеры

### Страница "Видеогалерея"

```
<section class="videos-section">
    <h1>Наши видео</h1>
    
    [[Gallery3xVideos?
        &fenom=`1`
        &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
        &sortby=`position`
        &sortdir=`ASC`
    ]]
</section>
```

### Боковая панель "Популярные видео"

```
<aside class="sidebar-widget">
    <h3>Популярные видео</h3>
    
    [[Gallery3xVideos?
        &tplOuter=`tpl.Gallery3x.Video.grid`
        &tplItem=`tpl.Gallery3x.Video.grid.item`
        &limit=`3`
        &sortby=`createdon`
        &sortdir=`DESC`
    ]]
</aside>
```

### Страница курса с уроками

```
<div class="course-lessons">
    <h2>Уроки курса</h2>
    
    [[Gallery3xVideos?
        &fenom=`1`
        &tplOuter=`tpl.Gallery3x.Video.embedded.fenom`
        &group=`Урок 1,Урок 2,Урок 3`
    ]]
</div>
```

### Главная страница (последние видео)

```
<section class="latest-videos">
    <div class="container">
        <h2>Новые видео</h2>
        
        [[Gallery3xVideos?
            &fenom=`1`
            &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
            &limit=`8`
            &sortby=`createdon`
            &sortdir=`DESC`
        ]]
        
        <a href="/videos/" class="btn-more">Все видео →</a>
    </div>
</section>
```

### Несколько разделов на странице

```
<h2>Обучающие видео</h2>
[[Gallery3xVideos?
    &fenom=`1`
    &group=`Обучение`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]

<h2>Отзывы клиентов</h2>
[[Gallery3xVideos?
    &fenom=`1`
    &group=`Отзывы`
    &tplOuter=`tpl.Gallery3x.Video.outer.fenom`
]]
```

---

Создание своего чанка

Скопируйте любой готовый чанк и измените под себя:

```
{* Мой кастомный чанк *}
<div class="my-videos">
    {foreach $videos as $video}
    <div class="my-video-card">
        <a href="{$video.url}" target="_blank">
            <img src="{$video.thumbnail_url}" alt="{$video.title}">
            <h3>{$video.title}</h3>
        </a>
    </div>
    {/foreach}
</div>
```

Используйте:

```
[[Gallery3xVideos?
    &fenom=`1`
    &tplOuter=`myCustomChunk`
]]
```

---

## Отладка

Включите режим отладки чтобы увидеть все данные:

```
[[Gallery3xVideos?
    &debug=`1`
]]
```

  
Пример использования видео с "родным" плеером Kinescope  
  
Fenom-версия (полная галерея в одном чанке):  
  
\[\[!Gallery3xVideos?  
 &amp;resource=`\[\[\*id\]\]`  
 &amp;tplOuter=`example.Gallery3x.Video.Kinescope.fenom`  
 &amp;fenom=`1`  
 &amp;where=`{"service":"kinescope"}`  
\]\]  
<span class="markdown-bold-text" style="color: rgba(228, 228, 228, 0.92); font-family: 'Segoe WPC', 'Segoe UI', sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(24, 24, 24); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; font-weight: 600;">  
Стандартный синтаксис MODX</span><span style="color: rgba(228, 228, 228, 0.92); font-family: 'Segoe WPC', 'Segoe UI', sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(24, 24, 24); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"> (отдельные чанки для обёртки и элемента):</span>  
\[\[!Gallery3xVideos?  
 &amp;resource=`\[\[\*id\]\]`  
 &amp;tplItem=`example.Gallery3x.Video.Kinescope`  
 &amp;where=`{"service":"kinescope"}`  
\]\]

# Gallery3xMixed

Объединённая галерея: изображения + видео

Компонент Gallery3x поддерживает объединённый вывод изображений и видео в одной галерее с группировкой!

Сниппет `Gallery3xMixed`

Объединяет изображения и видео с одного ресурса и выводит через Fenom-шаблон.

Параметры:  
\- `&amp;resource` - ID ресурса (по умолчанию текущий)  
\- `&amp;groupBy` - Поле для группировки (`group`, `resource\_id`, пустое для отключения)  
\- `&amp;sortby` - Поле сортировки (`position`, `createdon`, `id`)  
\- `&amp;sortdir` - Направление сортировки (`ASC` / `DESC`)  
\- `&amp;limit` - Ограничение количества элементов  
\- `&amp;showInactive` - Показывать неактивные (0/1)  
\- `&amp;tpl` - Шаблон вывода (по умолчанию `tpl.Gallery3x.Mixed.Fenom`)

\---

Примеры использования

Вариант 1: Простой вызов с группировкой

```
[[!Gallery3xMixed?
    &resource=`[[*id]]`
    &groupBy=`group`
    &sortby=`position`
]]
```

Результат:  
\- Все изображения и видео текущего ресурса  
\- Сгруппированы по полю `group`  
\- Каждая группа выводится отдельным блоком

\---

Вариант 2: Без группировки

```
[[!Gallery3xMixed?
    &resource=`[[*id]]`
    &groupBy=``
]]
```

Результат: плоский список всех медиафайлов без группировки

\---

Вариант 3: Ограничение количества

```
[[!Gallery3xMixed?
    &resource=`[[*id]]`
    &groupBy=`group`
    &limit=`12`
]]
```

Результат: только первые 12 элементов

\---

Вариант 4: Свой шаблон Fenom

Создайте свой чанк и укажите его:

```
[[!Gallery3xMixed?
    &resource=`[[*id]]`
    &groupBy=`group`
    &tpl=`tpl.My.Custom.Gallery`
]]
```

Пример кастомного шаблона `tpl.My.Custom.Gallery`:

```
{set $gallery = $_modx->getPlaceholder('myGallery')}

{if $gallery}
<div class="my-custom-gallery">
    {foreach $gallery as $groupName => $items}
        <section class="gallery-section">
            <h2>{$groupName}</h2>
            <div class="items-grid">
                {foreach $items as $item}
                    <div class="item {$item.media_type}">
                        {* unique_id выглядит как: img_5 или video_3 *}
                        <div class="item-id">{$item.unique_id}</div>
                        
                        {if $item.media_type == 'image'}
                            <img src="{$item.thumb}" alt="{$item.title}">
                            <p>{$item.name}</p>
                        {else}
                            <img src="{$item.thumb}" alt="{$item.title}">
                            <a href="{$item.url}">▶️ {$item.title}</a>
                            <p>Сервис: {$item.service}</p>
                        {/if}
                    </div>
                {/foreach}
            </div>
        </section>
    {/foreach}
</div>
{/if}
```

\---

Структура возвращаемых данных

Каждый элемент содержит:

Общие поля:  
\- `unique\_id` - уникальный ID (`img\_5` или `video\_3`)  
\- `media\_type` - тип (`image` или `video`)  
\- `title` - название  
\- `thumb` - URL миниатюры  
\- `url` - URL оригинала  
\- `group` - группы через `||`  
\- `active` - активность (0/1)  
\- `position` - позиция для сортировки

Только для изображений:  
\- `name` - имя файла  
\- `file` - имя файла  
\- `path` - путь к файлу  
\- `original\_url` - URL оригинала  
\- `small\_url`, `medium\_url`, `large\_url` - размеры

Только для видео:  
\- `service` - видеохостинг (`rutube`, `youtube`, `vk`)  
\- `video\_id` - ID видео на хостинге  
\- `description` - описание  
\- `duration` - длительность  
\- `author` - автор  
\- `thumbnail\_url` - URL обложки

# Gallery3xFiles

## Gallery3xFiles

Сниппет для вывода файловых вложений ресурса на фронтенде сайта. Отображает файлы, загруженные через вкладку «Файлы G3x» в редакторе ресурса MODX. Поддерживает фильтрацию, сортировку, группировку и вывод через Fenom или стандартный синтаксис MODX.

---

### Параметры

<table id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%A2%D0%B8%D0%BF-%D0%9F%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB"><thead><tr><th>Параметр</th><th>Тип</th><th>По умолчанию</th><th>Описание</th></tr></thead><tbody><tr><td>`resource`</td><td>int</td><td>ID текущего ресурса</td><td>ID ресурса, файлы которого выводятся</td></tr><tr><td>`resources`</td><td>string</td><td>—</td><td>Список ID ресурсов через запятую. Отрицательное значение исключает ресурс (например: `5,10,-3`)</td></tr><tr><td>`parents`</td><td>string</td><td>—</td><td>ID родительских ресурсов через запятую. Выводятся файлы всех дочерних ресурсов (глубина до 10 уровней)</td></tr><tr><td>`group`</td><td>string</td><td>—</td><td>Фильтр по группе или нескольким группам через запятую. Поддерживается мультигруппа</td></tr><tr><td>`limit`</td><td>int</td><td>`0`</td><td>Максимальное количество файлов. `0` — без ограничения</td></tr><tr><td>`offset`</td><td>int</td><td>`0`</td><td>Смещение выборки (для пагинации)</td></tr><tr><td>`sortby`</td><td>string</td><td>`position`</td><td>Поле сортировки: `position`, `name`, `size`, `createdon`, `type`</td></tr><tr><td>`sortdir`</td><td>string</td><td>`ASC`</td><td>Направление сортировки: `ASC` или `DESC`</td></tr><tr><td>`showInactive`</td><td>int</td><td>`0`</td><td>Показывать деактивированные файлы. `1` — показывать</td></tr><tr><td>`where`</td><td>JSON</td><td>—</td><td>Дополнительные условия xPDO-запроса в формате JSON. Например: `{"type":"pdf"}`</td></tr><tr><td>`tplOuter`</td><td>string</td><td>`tpl.Gallery3x.Files.outer`</td><td>Чанк-обёртка всего списка</td></tr><tr><td>`tplItem`</td><td>string</td><td>`tpl.Gallery3x.Files.item`</td><td>Чанк одного файла (используется при стандартном синтаксисе MODX)</td></tr><tr><td>`fenom`</td><td>int</td><td>`0`</td><td>Использовать Fenom для рендеринга. Требует pdoTools. При `1` весь массив передаётся в `tplOuter`</td></tr><tr><td>`return`</td><td>string</td><td>—</td><td>Вернуть данные вместо HTML: `data` — PHP-массив, `json` — JSON-строка, `ids` — массив ID</td></tr><tr><td>`toPlaceholder`</td><td>string</td><td>—</td><td>Сохранить результат в указанный плейсхолдер вместо вывода на страницу</td></tr><tr><td>`debug`</td><td>int</td><td>`0`</td><td>Режим отладки. При `1` выводит параметры запроса и данные найденных файлов</td></tr></tbody></table>

---

### Доступные поля в шаблонах

Каждый элемент содержит следующие поля:

<table id="bkmrk-%D0%9F%D0%BE%D0%BB%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-id-id-"><thead><tr><th>Поле</th><th>Описание</th></tr></thead><tbody><tr><td>`id`</td><td>ID записи в базе данных</td></tr><tr><td>`resource_id`</td><td>ID ресурса MODX</td></tr><tr><td>`file`</td><td>Имя файла</td></tr><tr><td>`path`</td><td>Относительный путь к папке файла</td></tr><tr><td>`url`</td><td>Полный URL файла через медиасорс</td></tr><tr><td>`name`</td><td>Заголовок файла (заданный вручную)</td></tr><tr><td>`description`</td><td>Описание файла</td></tr><tr><td>`type`</td><td>MIME-тип файла</td></tr><tr><td>`ext`</td><td>Расширение файла в нижнем регистре (например, `pdf`, `zip`)</td></tr><tr><td>`size`</td><td>Размер файла в байтах</td></tr><tr><td>`size_formatted`</td><td>Размер файла в читаемом виде: `1.2 MB`, `340 KB`, `512 B`</td></tr><tr><td>`group`</td><td>Группы через разделитель `||` (внутренний формат хранения)</td></tr><tr><td>`groups_list`</td><td>Группы через запятую (удобно для вывода в шаблоне)</td></tr><tr><td>`active`</td><td>Активность: `1` — активен, `0` — скрыт</td></tr><tr><td>`position`</td><td>Порядковый номер сортировки</td></tr><tr><td>`createdon`</td><td>Дата загрузки (Unix timestamp)</td></tr></tbody></table>

В `tplOuter` дополнительно передаются:

<table id="bkmrk-%D0%9F%D0%BE%D0%BB%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-total-"><thead><tr><th>Поле</th><th>Описание</th></tr></thead><tbody><tr><td>`total`</td><td>Общее количество найденных файлов</td></tr><tr><td>`first`</td><td>Массив данных первого файла (для быстрого доступа)</td></tr><tr><td>`files`</td><td>Весь массив файлов (только при Fenom)</td></tr><tr><td>`items`</td><td>Готовый HTML из всех `tplItem` (только при стандартном синтаксисе)</td></tr></tbody></table>

---

### Примеры вызова

**Минимальный (текущий ресурс, стандартный синтаксис):**

```
[[!Gallery3xFiles]]
```

**С Fenom:**

```
[[!Gallery3xFiles?
    &tplOuter=`tpl.Gallery3x.Files.outer.fenom`
    &fenom=`1`
]]
```

**Фильтр по группе, ограничение количества:**

```
[[!Gallery3xFiles?
    &group=`документы`
    &limit=`10`
    &sortby=`name`
    &sortdir=`ASC`
]]
```

**Файлы нескольких ресурсов:**

```
[[!Gallery3xFiles?
    &resources=`5,10,15`
    &fenom=`1`
    &tplOuter=`tpl.Gallery3x.Files.outer.fenom`
]]
```

**Получить JSON (для JavaScript или Fenom-обработки):**

```
[[!Gallery3xFiles?
    &return=`json`
]]
```

**Сохранить в плейсхолдер:**

```
[[!Gallery3xFiles?
    &toPlaceholder=`myFiles`
]]
```

**Фильтрация через `where` (только PDF):**

```
[[!Gallery3xFiles?
    &where=`{"type":"application/pdf"}`
]]
```

# Плейсхолдеры изображений

Функция "Плейсхолдеры изображений" — это мощный инструмент, который позволяет выводить изображения из галереи **напрямую в контенте или шаблоне ресурса**, не вызывая сниппет.

Специальный плагин один раз подготавливает все данные и делает их доступными в виде простых плейсхолдеров, таких как `[[+g3x.0]]` или `[[+g3x.1.url]]`.

### Как это работает

При загрузке страницы на сайте плагин, работающий на событии `OnLoadWebDocument`, выполняет следующие действия:

1. Проверяет, включена ли эта функция в системных настройках.
2. Если да, он находит все **активные** изображения для текущего ресурса, сортируя их по полю `position`.
3. Для каждого найденного изображения создается набор плейсхолдеров, которые MODX может использовать при обработке страницы.

### Системные настройки

Для управления этой функцией используются четыре системные настройки в пространстве имен `gallery3x`.

#### 1. Включить плейсхолдеры на сайте

- **Ключ:** `gallery3x.set_placeholders`
- **Описание:** Главный "рубильник". Установите в "Да", чтобы активировать функцию. По умолчанию выключено, так как создает дополнительный запрос к базе данных на каждой странице. **Включайте, только если вы действительно используете плейсхолдеры в шаблонах или контенте.**

#### 2. Чанк для плейсхолдеров

- **Ключ:** `gallery3x.placeholders_tpl`
- **Описание:** Имя чанка, который будет использоваться для оформления плейсхолдера вида `[[+g3x.N]]`. Если эта настройка пуста, то `[[+g3x.0]]` просто выведет массив данных картинки. Если указан чанк, его содержимое будет обработано с данными картинки.
- **Пример значения:** `tpl.Gallery3x.placeholderItem`

#### 3. Включить для шаблонов

- **Ключ:** `gallery3x.placeholders_for_templates`
- **Описание:** Список ID шаблонов через запятую, для которых будет работать эта функция. Это позволяет включать плейсхолдеры только для нужных разделов, например, для карточек товаров или статей в блоге, экономя ресурсы на остальных страницах.
- **Пример значения:** `3, 8, 12`
- **Примечание:** Если поле пустое, функция будет работать для **всех** шаблонов.

#### 4. Размеры превью для плейсхолдеров

- **Ключ:** `gallery3x.placeholders_thumbs`
- **Описание:** Список размеров превью через запятую, которые нужно сделать доступными в плейсхолдерах. Это полезная оптимизация, которая не позволяет загружать лишние данные.
- **Пример значения:** `small,medium`

---

### Примеры использования

Предположим, вы загрузили в галерею 3 картинки.

#### 1. Простой вывод

Вы можете вставить эти плейсхолдеры прямо в контент ресурса или в его шаблон:

- `[[+g3x.0.url]]` — выведет URL **оригинала** первой картинки.
- `[[+g3x.0.medium]]` — выведет URL превью размера `medium` первой картинки.
- `[[+g3x.1.alt]]` — выведет `alt` текст второй картинки.
- `[[+g3x.2.name]]` — выведет название третьей картинки.

#### 2. Вывод с форматированием (через чанк)

Это основной способ использования.

1. Создайте чанк, например, `tpl.Gallery3x.placeholderItem` со следующим кодом:
    
    <div _ngcontent-ng-c2485367380="" class="code-block ng-tns-c2485367380-130 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_ade0b4c3dcc9b299","c_b8511ae2af5280fd",null,"rc_948f3922e4ce7d69",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2485367380="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2485367380-130 ng-star-inserted"><span class="ng-tns-c2485367380-130">HTML</span><div _ngcontent-ng-c2485367380="" class="buttons ng-tns-c2485367380-130 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2485367380-130 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div></div>```
    <a href="[[+url]]" class="image-link">
        <img src="[[+medium]]" alt="[[+alt]]" title="[[+name]]">
    </a>
    
    ```
    
    <div _ngcontent-ng-c2485367380="" class="code-block ng-tns-c2485367380-130 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_ade0b4c3dcc9b299","c_b8511ae2af5280fd",null,"rc_948f3922e4ce7d69",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2485367380="" class="formatted-code-block-internal-container ng-tns-c2485367380-130"><div _ngcontent-ng-c2485367380="" class="animated-opacity ng-tns-c2485367380-130"></div></div></div>
2. В системной настройке `gallery3x.placeholders_tpl` укажите имя этого чанка: `tpl.Gallery3x.placeholderItem`.
3. Теперь вы можете вставлять в контент просто `[[+g3x.0]]`, `[[+g3x.1]]` и т.д., и они будут автоматически обернуты в HTML из вашего чанка.

#### 3. Продвинутое использование (с Fenom)

Если на сайте используется Fenom, вы можете легко перебрать все изображения в цикле прямо в шаблоне:

```
{if $_modx->resource.g3x.0}
    <div class="product-gallery">
        <div class="main-image">
            <img src="{$_modx->resource['g3x.0.medium']}" alt="{$_modx->resource['g3x.0.alt']}">
        </div>
        <div class="thumbnails">
            {for $i = 0 to 10}
                {if $_modx->resource["g3x.{$i}.small"]}
                    <img src="{$_modx->resource["g3x.{$i}.small"]}" alt="">
                {/if}
            {/for}
        </div>
    </div>
{/if}
```

# Примеры

# Lightgallery



# Fancybox

Демо сайт [https://demog3x.ivan345.com/](https://demog3x.ivan345.com/), примеры с Fancybox

# pdoResources

Пример использования pdoResources, выводит ресурсы MODX, а в качестве изображения используется 1 изображения из галереи.

```
[[!pdoResources?
    
    
    &tpl=`ListRowTpl`
    &includeContent=`1`
    &leftJoin=`{
        "Image": {
            "class": "Gallery3x\\Model\\Gallery3xFile",
            "on": "modResource.id = Image.resource_id AND Image.position = 0 AND Image.active = 1"
        }
    }`
    &select=`{
        "modResource": "*",
        "Image": "Image.id as image_id, Image.alt as image_alt"
    }`
]]
```

#### Чанк ListRowTpl  


```
{* Вызываем сниппет g3xGetImage, передавая ему ID картинки *}<br></br>{set $image_url = $_pls['image_id'] | g3xGetImage : 'small'}<br></br>{set $uri = $_modx->makeUrl($_pls.id)}<br></br><br></br><div class="catalog-item"><br></br>    {$image_url}<br></br>    {if $image_url}<br></br>        <a href="{$uri = $_modx->makeUrl($_pls.id)}"><br></br>            <img src="{$image_url}" alt="{$_pls['image_alt'] ?: $_pls['pagetitle']}"><br></br>        </a><br></br>    {else}<br></br>        <a href="{$_pls.uri}"><br></br>            <img src="/assets/images/no-image.png" alt="{$_pls.pagetitle}"><br></br>        </a><br></br>    {/if}<br></br><br></br>    <h3><a href="{$uri}">{$_pls.pagetitle}</a></h3><br></br>    <p>{$_pls.introtext}</p><br></br></div>
```

# Интеграция с компонентом Collections

Вот как выводить превью первого изображения из галереи `Gallery3x` прямо в таблице дочерних ресурсов компонента **Collections**.

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

#### Подключение JS-рендера в системных настройках

[![Screenshot_1.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-09/scaled-1680-/ae8KVcEPj73BC9fA-screenshot-1.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-09/ae8KVcEPj73BC9fA-screenshot-1.jpg)

Теперь нужно "сказать" компоненту Collections, чтобы он загружал JS-файл.

1. Перейдите в **Настройки (⚙️) → Системные настройки**.
2. В фильтре выберите пространство имен **collections**.
3. Найдите ключ **`collections.user_js`** (Пользовательский JS-файл).
4. Впишите в него путь к файлу: `/assets/components/gallery3x/js/mgr/misc/renderers.js`

#### Настройка колонки в Collections

Это финальный шаг, где мы связываем всё вместе.

1. Перейдите на ресурс-контейнер и откройте настройки вида Collections (вкладка "Дочерние ресурсы" → ⚙️).
2. Откройте на редактирование или создайте новую колонку со следующими параметрами:
    
    
    - **Заголовок:** `Превью`
    - **Название:** `g3xCollectionsThumbnail`
    - **Рендерер:** `Gallery3x.renderer.image`
    - **Сниппет-рендер:** `g3xCollectionsThumbnail`
    - #### `<a href="https://docs.ivan345.com/uploads/images/gallery/2025-09/RXODGq3eZw1gYZ7K-screenshot-2.jpg" rel="noopener" target="_blank"><img alt="Screenshot_2.jpg" src="https://docs.ivan345.com/uploads/images/gallery/2025-09/scaled-1680-/RXODGq3eZw1gYZ7K-screenshot-2.jpg"></img></a>`  
          
          
        Результат:  
          
        [![Screenshot_3.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-09/scaled-1680-/X02TCQqiUpjGEYPC-screenshot-3.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-09/X02TCQqiUpjGEYPC-screenshot-3.jpg)

# Работа из командной строки (CLI)

# regenerate.php

Компонент `Gallery3x` включает в себя скрипты для выполнения задач обслуживания и массовой обработки данных напрямую из консоли (терминала) вашего сервера по SSH. Это гораздо быстрее и эффективнее для больших объемов данных, чем выполнение тех же действий через браузер.

## Перегенерация всех превью

Со временем вам может понадобиться обновить все миниатюры в галерее. Например, если вы изменили настройки водяного знака, добавили новый размер превью или изменили параметры фильтров в системных настройках.

Для этой задачи предназначен скрипт `regenerate.php`.

### Использование

1. Подключитесь к вашему серверу по **SSH**.
2. Перейдите в **корневую директорию** вашего сайта MODX (там, где находится папка `core`).
3. Выполните следующую команду:
    
    <div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-148 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_740f69ae35b68b9f","c_b8511ae2af5280fd",null,"rc_1a52e10e40078708",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="code-block-decoration header-formatted gds-title-s ng-tns-c1906655948-148 ng-star-inserted"><span class="ng-tns-c1906655948-148">Bash</span><div _ngcontent-ng-c1906655948="" class="buttons ng-tns-c1906655948-148 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c1906655948-148 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-148"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-148"></div></div></div>```
    php core/components/gallery3x/cli/regenerate.php
    
    ```
    
    <div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-148 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[["r_740f69ae35b68b9f","c_b8511ae2af5280fd",null,"rc_1a52e10e40078708",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-148"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-148"></div></div></div>

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

<div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-149 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression;BardVeMetadataKey:[["r_740f69ae35b68b9f","c_b8511ae2af5280fd",null,"rc_1a52e10e40078708",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-149"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-149"></div></div></div>```
MODX Initialized. Starting regeneration...
Found 58 files to process.

Processing file ID: 1 (Resource: 2, Filename: photo1.jpg)
Processing file ID: 2 (Resource: 2, Filename: photo2.webp)
...
Processing file ID: 58 (Resource: 15, Filename: another.png)

----------------------------------------
Done! Regenerated thumbnails for 58 of 58 files.
Site cache has been cleared.

```

<div _ngcontent-ng-c1906655948="" class="code-block ng-tns-c1906655948-149 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--2" jslog="223238;track:impression;BardVeMetadataKey:[["r_740f69ae35b68b9f","c_b8511ae2af5280fd",null,"rc_1a52e10e40078708",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c1906655948="" class="formatted-code-block-internal-container ng-tns-c1906655948-149"><div _ngcontent-ng-c1906655948="" class="animated-opacity ng-tns-c1906655948-149"></div></div></div>После завершения работы скрипта все превью для всех изображений в компоненте `Gallery3x` будут пересозданы с учетом самых последних настроек. В конце скрипт автоматически очистит кеш сайта.

# import_ms2gallery.php

# Импорт из ms2Gallery

Компонент `Gallery3x` включает в себя консольный скрипт для миграции изображений из старого компонента `ms2Gallery`. Это позволяет легко и быстро перенести все существующие галереи на новый, современный движок `Gallery3x` при переезде с MODX 2 на MODX 3.

**Ключевая особенность:** Скрипт работает, даже если вы **уже удалили** пакет `ms2Gallery` из админ-панели. Главное, чтобы его таблица (`modx_ms2_resource_files`) и физические файлы остались на сервере.

### Использование скрипта

- **Автоматизация:** Скрипт автоматически переносит тысячи файлов и их метаданные.
- **Использование процессора:** Для каждого файла вызывается стандартный процессор загрузки `Gallery3x`, что гарантирует применение **всех ваших текущих настроек** (транслитерация, водяные знаки, фильтры, генерация превью).
- **Сохранение данных:** Скрипт переносит не только сами файлы, но и всю важную информацию: название, описание, alt-тег, статус (активен/неактивен) и порядок сортировки.

---

### Подготовка к импорту

Перед запуском убедитесь, что:

1. Старая таблица `ms2Gallery` (обычно `префикс_ms2_resource_files`) все еще существует в вашей базе данных.
2. Физические файлы, загруженные через `ms2Gallery`, все еще находятся на сервере.

---

### Настройка и запуск скрипта

Вся настройка производится прямо в файле скрипта.

1. **Откройте файл скрипта** в текстовом редакторе. Он находится по пути: `/core/components/gallery3x/cli/import_ms2gallery.php`
2. **Настройте параметры** в самом верху файла:
    
    <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2011 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0Qo" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2201599828-2011 ng-star-inserted"><span class="ng-tns-c2201599828-2011">PHP</span><div _ngcontent-ng-c2201599828="" class="buttons ng-tns-c2201599828-2011 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2201599828-2011 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2011"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2011">  
    </div></div></div>```
    // ===================================================================
    // --- НАСТРОЙКИ ИМПОРТА: Укажите ваши значения здесь ---
    // ===================================================================
    
    // ID ресурса для импорта. Укажите 0, чтобы импортировать для ВСЕХ ресурсов.
    $resourceId = 0;
    
    // "Сухой" запуск. 
    // true  - скрипт только покажет, какие файлы он нашел, но ничего не будет импортировать.
    // false - скрипт выполнит реальный импорт.
    $isDryRun = true;
    
    ```
    
    <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2011 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0Qo" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2011"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2011"></div></div></div>
3. **Запустите скрипт из консоли (терминала) по SSH.** Сначала всегда запускайте в "сухом" режиме, чтобы убедиться, что скрипт правильно находит ваши файлы. Для этого `$isDryRun` должен быть `true`.
    
    
    - Перейдите в корневую директорию вашего сайта.
    - Выполните команду:
        
        <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2012 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0go" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2201599828-2012 ng-star-inserted"><span class="ng-tns-c2201599828-2012">Bash</span><div _ngcontent-ng-c2201599828="" class="buttons ng-tns-c2201599828-2012 ng-star-inserted"><button aria-label="Скопировать код" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2201599828-2012 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2012"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2012">  
        </div></div></div>```
        php core/components/gallery3x/cli/import_ms2gallery.php
        
        ```
        
        <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2012 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0go" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2012"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2012"></div></div></div>
    - Вы увидите в консоли отчет о том, сколько файлов найдено для импорта.
4. **Запустите реальный импорт.**
    
    
    - Если "сухой" запуск прошел успешно, измените в файле скрипта `$isDryRun = false;`.
    - Сохраните файл и выполните ту же команду в консоли еще раз.
    
    Начнется процесс копирования файлов, создания записей в базе и генерации превью.
    
    <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2013 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0wo" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2013"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2013">  
    </div></div></div>```
    MODX Initialized. Starting ms2Gallery import...
    Found 150 files to process.
    
    Processing file: /path/to/site/assets/images/products/12/photo1.jpg
     -> SUCCESS: Imported to Gallery3x file ID 210
    
    Processing file: /path/to/site/assets/images/products/12/photo2.jpg
     -> SUCCESS: Imported to Gallery3x file ID 211
    ...
    ----------------------------------------
    SUCCESS: Imported 150 of 150 found files.
    Site cache has been cleared.
    
    ```
    
    <div _ngcontent-ng-c2201599828="" class="code-block ng-tns-c2201599828-2013 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiClOCvksyPAxUAAAAAHQAAAAAQ0wo" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5ab0af49da82072d","c_b8511ae2af5280fd",null,"rc_d5557a3270d24242",null,null,"ru",null,1,null,null,1,0]]" style="display: block;"><div _ngcontent-ng-c2201599828="" class="formatted-code-block-internal-container ng-tns-c2201599828-2013"><div _ngcontent-ng-c2201599828="" class="animated-opacity ng-tns-c2201599828-2013"></div></div></div>

---

### После импорта

1. **Проверьте результат:** Зайдите в админ-панели на страницы ресурсов и убедитесь, что изображения появились во вкладке "Галерея" компонента `Gallery3x`.
2. **Проверьте сайт:** Убедитесь, что галереи на сайте отображаются правильно.
3. **Очистка (опционально):** Когда вы будете полностью уверены, что миграция прошла успешно, вы можете вручную удалить старую таблицу `modx_ms2_resource_files` из базы данных, чтобы она не занимала место.

# Для разработчиков

# Структура Базы Данных

# Структура Базы Данных (Для разработчиков)

Компонент `Gallery3x` хранит данные в двух отдельных таблицах: одна для **файлов** (изображений) и одна для **видео**. Такое разделение позволяет гибко управлять каждым типом данных.

Вы можете взаимодействовать с этими таблицами, используя xPDO и соответствующие классы модели.

---

## Таблица Файлов (gallery3x\_files)

Здесь хранятся все загруженные файлы (в основном, изображения).

- **Имя класса:** `Gallery3x\Model\Gallery3xFile`
- **Имя таблицы:** `[[+modx.config.table_prefix]]gallery3x_files`

### Поля объекта `Gallery3xFile`

<table id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%28%D0%9F%D0%BE%D0%BB%D0%B5%29-%D0%A2%D0%B8%D0%BF-%D0%94%D0%B0%D0%BD%D0%BD" style="margin-bottom: 32px; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><thead style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Ключ (Поле)**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Тип Данных**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Описание**</td></tr></thead><tbody style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Уникальный ID записи</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`resource_id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID ресурса MODX, к которому привязан файл.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`source_id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID источника файлов (modMediaSource).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`parent_id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Зарезервировано для будущих функций.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`name`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Название файла (может быть отредактировано).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`description`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Описание файла.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`alt`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ALT-тег изображения.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`path`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Путь к файлу внутри источника (напр. `15/`).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`file`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Имя файла (напр. `image.jpg`).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`type`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">MIME-тип файла (`image/jpeg`).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`size`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Размер файла в байтах.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`position`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Позиция для сортировки.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`group`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**(Новое)** Группа (тег) для файла (напр. "Интерьер").</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`properties`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">json</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">JSON-массив с данными (превью, размеры).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`createdon`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">datetime</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Дата создания.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`createdby`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID пользователя, создавшего запись.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`updatedon`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">datetime</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Дата последнего обновления.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`updatedby`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID пользователя, обновившего запись.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`active`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">boolean</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Статус (1 = активен, 0 = скрыт).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`hash`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Хеш файла для проверки на дубликаты.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`special`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">boolean</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**(Новое)** Статус "Особенное" (1 = да, 0 = нет).</td></tr></tbody></table>

---

## Таблица Видео (gallery3x\_videos)

Здесь хранятся ссылки на видео и связанные с ними данные.

- **Имя класса:** `Gallery3x\Model\Gallery3xVideo`
- **Имя таблицы:** `[[+modx.config.table_prefix]]gallery3x_videos`

### Поля объекта `Gallery3xVideo`

<table id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%28%D0%9F%D0%BE%D0%BB%D0%B5%29-%D0%A2%D0%B8%D0%BF-%D0%94%D0%B0%D0%BD%D0%BD-1" style="margin-bottom: 32px; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><thead style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Ключ (Поле)**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Тип Данных**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Описание**</td></tr></thead><tbody style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Уникальный ID записи</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`resource_id`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID ресурса MODX, к которому привязано видео.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`url`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Полная ссылка на видео (YouTube, VK и т.д.).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`title`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Название видео (вводится пользователем).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`description`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Описание видео.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`thumbnail`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**Путь к файлу превью** (загружается вручную).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`position`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Позиция для сортировки.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`group`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Группа (тег) для видео.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`service`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">*На будущее:* Сервис видео (youtube, vk).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`video_id`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">string</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">*На будущее:* ID видео на сервисе.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`createdon`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">datetime</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Дата создания.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`createdby`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID пользователя, создавшего запись.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`updatedon`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">datetime</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Дата последнего обновления.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`updatedby`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">integer</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">ID пользователя, обновившего запись.</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">`active`</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">boolean</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Статус (1 = активен, 0 = скрыт).</td></tr><tr style="font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;"><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">**`special`**</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">boolean</td><td style="border: 1px solid; font-family: 'Google Sans Text', sans-serif !important; line-height: 1.15 !important; margin-top: 0px !important;">Статус "Особенное" (1 = да, 0 = нет).</td></tr></tbody></table>

# Группы (теги) для фотографий

#### Группы (теги) для фотографий

Описание

Начиная с версии \*\*3.0.17\*\*, Gallery3x поддерживает группировку фотографий с помощью групп (тегов). Одной фотографии можно присвоить несколько групп одновременно, что позволяет гибко организовывать и фильтровать изображения.

##### Ключевые особенности:  
✅ Множественный выбор групп для одной фотографии  
✅ Глобальные группы доступны во всех галереях компонента  
✅ Быстрая фильтрация по группам в панели управления  
✅ Массовое присвоение групп выбранным фотографиям  
✅ Удобный интерфейс с визуальными "таблетками"

\---

##### Создание групп

Группы создаются динамически при редактировании фотографий. Для создания новой группы:

1\. Откройте контекстное меню на фотографии (правый клик)  
2\. Выберите "Изменить свойства"  
3\. В поле "Группа" начните вводить название группы (например, "Пейзаж")  
4\. ⚠️ ОБЯЗАТЕЛЬНО нажмите клавишу `Enter` — группа превратится в "таблетку" с крестиком  
5\. Повторите для добавления других групп  
6\. Нажмите "Сохранить"

&gt; 💡 Важно: Без нажатия `Enter` группа не будет создана! После нажатия `Enter` вы увидите, что текст превратился в цветную "таблетку" — это означает, что группа добавлена.

\---

Присвоение групп одной фотографии

Способ 1: Через свойства фотографии

1\. Правый клик на фотографии → "Изменить свойства"  
2\. В поле "Группа" введите название и нажмите `Enter`  
3\. Добавьте еще группы (каждый раз нажимая `Enter`)  
4\. Нажмите "Сохранить"

Способ 2: Выбор существующих групп

1\. Правый клик на фотографии → "Изменить свойства"  
2\. Кликните в поле "Группа" — откроется выпадающий список  
3\. Выберите существующие группы из списка (они уже созданы ранее)  
4\. Или введите новую группу и нажмите `Enter`  
5\. Нажмите "Сохранить"

\---

Массовое присвоение групп

Вы можете присвоить группы сразу нескольким фотографиям:

1\. Выделите несколько фотографий (удерживая `Ctrl` или `Shift`)  
2\. Правый клик → "Установить группу..."  
3\. В открывшемся окне выберите или создайте группы (не забывайте нажимать `Enter`)  
4\. Нажмите "Сохранить"  
5\. Группы будут \*\*добавлены\*\* к уже существующим группам этих фотографий

\---

Фильтрация по группам

В верхней панели галереи находится фильтр по группам:

1\. Откройте выпадающий список \*\*"Фильтр по группе:"\*\*  
2\. Выберите нужную группу  
3\. Галерея покажет только фотографии с этой группой  
4\. Для сброса фильтра нажмите кнопку \*\*"Сбросить"\*\*

\---

Удаление групп

Удаление группы у фотографии:

1.Правый клик на фотографии → "Изменить свойства"  
2\. Нажмите \*\*крестик (×)\*\* на "таблетке" нужной группы  
3\. Нажмите \*\*"Сохранить"\*\*

Удаление группы полностью:

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

\---

Где отображаются группы

\- В админке: Под каждой фотографией показываются все её группы через запятую  
\- В базе данных: Группы хранятся в поле `group` таблицы `gallery3x\_files` через разделитель `||` (стандарт MODX)

\---

Примеры использования

Пример 1: Организация по темам  
\- Создайте группы: `Природа`, `Архитектура`, `Люди`, `Животные`  
\- Присвойте фотографиям соответствующие группы  
\- Используйте фильтр для быстрого поиска нужной категории

Пример 2: Множественная классификация  
\- Фотографии могут иметь несколько групп: `Зима`, `Пейзаж`, `Закат`  
\- Это позволяет находить фото по разным критериям

Пример 3: Массовая работа  
\- Выделите 20 фотографий с одного мероприятия  
\- Присвойте им группу `Конференция 2025`  
\- Добавьте дополнительную группу `Корпоратив` некоторым из них

\---

Часто задаваемые вопросы (FAQ)

Q: Я ввожу название группы, но она не сохраняется. Почему?  
A: Вы забыли нажать клавишу \*\*`Enter`\*\* после ввода названия. Группа должна превратиться в "таблетку" с крестиком.

Q: Группы, созданные в одной галерее, видны в другой?  
A: Да! Группы теперь глобальные и доступны во всех галереях компонента.

Q: Можно ли переименовать группу?  
A: Нет, но вы можете удалить старую группу у всех фотографий и создать новую с нужным названием.

Q: Сколько групп можно присвоить одной фотографии?  
A: Неограниченное количество.

\---

Технические детали

\- Формат хранения: Группы хранятся в поле `group` через разделитель `||` (например: `Природа||Пейзаж||Зима`)  
\- Компонент UI:Используется стандартный MODX SuperBoxSelect  
\- Процессоры: `File/GetGroups`, `File/BulkSetGroup`, `File/Update`

# Кастомизация процессора получения групп (тэгов)

#####   
  
Как создать свой процессор:   


  
Пример: Фильтрация по resource\_id (Что группы были для каждого ресурса свои и не повторялись в других)  
Создайте файл: в core/components/gallery3x/src/Processors/GetGroupsByResource.php

```
<?php
namespace Gallery3x\Processors;
use Gallery3x\Model\Gallery3xFile;

class GetGroupsByResource extends GetGroupsCombined
{
    public function process()
    {
        $resourceId = $this->getProperty('resource_id');
        $allGroups = [];

        // Только для текущего ресурса
        $fileTableName = $this->modx->getTableName(Gallery3xFile::class);
        $sql = "SELECT DISTINCT `group` FROM {$fileTableName} 
                WHERE `group` IS NOT NULL 
                AND `group` != '' 
                AND `resource_id` = :resource_id
                ORDER BY `group` ASC";

        $stmt = $this->modx->prepare($sql);
        $stmt->bindValue(':resource_id', $resourceId);

        if ($stmt->execute()) {
            while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
                $groupsInRow = explode('||', $row['group']);
                foreach ($groupsInRow as $group) {
                    $group = trim($group);
                    if (!empty($group)) {
                        $allGroups[] = $group;
                    }
                }
            }
        }

        // То же для видео...

        $uniqueGroups = array_unique($allGroups);
        sort($uniqueGroups);

        $groups = [];
        foreach ($uniqueGroups as $group) {
            $groups[] = ['name' => $group];
        }

        return $this->success('', ['results' => $groups, 'total' => count($groups)]);
    }
}
```

##### Затем в настройках:

  
gallery3x.groups\_processor = Gallery3x\\Processors\\GetGroupsByResource

# API интеграции

# API VK.com

**Почему-то не всем юзерам VK выдает разрешение использовать API, предупреждаю сразу**  
  
Для работы с API VK нужно сделать  
1\) Создать приложение по адресу [https://id.vk.com/about/business/go/](https://id.vk.com/about/business/go/) Нужно расширить свой аккаунт до "Бизнес" я подтвердил его через гос. услуги как физ. лицо.

[![vk1.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-11/scaled-1680-/wpspSX9YL74aWlEH-vk1.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-11/wpspSX9YL74aWlEH-vk1.jpg)

[![vk2.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-11/scaled-1680-/VPPEwv9xz3vUVqWT-vk2.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-11/VPPEwv9xz3vUVqWT-vk2.jpg)

  
2\) При создании приложения указываете свой базовый домен   
  
Домен: moydomen.ru  
Доверенный Redirect URL: [https://moydomen.ru/assets/components/gallery3x/vk-callback.php](https://moydomen.ru/assets/components/gallery3x/vk-callback.php) (нужно к домену добавить assets/components/gallery3x/vk-callback.php)

3\) После создания приложения, запишите id приложение его нужно вписать в настройках компонента.

Самый главный шаг нужно написать в тех. поддержку в контакте https://vk.com/dont\_panic\_42

Вот пример такого запроса:

```
Здравствуйте, команда поддержки ВКонтакте!

Я обращаюсь к вам с просьбой рассмотреть и одобрить добавление права доступа (scope) video для моего приложения:


ID приложения: [ВАШ ID ПРИЛОЖЕНИЯ]
Сайт, на котором используется: [АДРЕС ВАШЕГО САЙТА, например: https://my-site.ru]
Обоснование (Зачем нам это нужно):
Наш сайт работает на CMS MODX Revolution, и мы используем компонент "Gallery3x" для управления фото- и видеогалереями. Этот компонент позволяет нашим контент-менеджерам легко добавлять видео из VK на страницы сайта.
Для максимального удобства наших редакторов компонент использует метод video.get.


Как это будет работать:
1.    Наш контент-менеджер вставляет в админ-панели сайта публичную ссылку на видео из VK.
2.    Наш сервер (через компонент) делает однократный вызов video.get, чтобы получить публичные метаданные этого видео: title (название), description (описание) и image (обложку).
3.    Эти данные автоматически заполняют поля в нашей админ-панели. Это избавляет редактора от необходимости копировать все вручную и сильно экономит время.
Нам требуется доступ только для чтения (read-only) метаданных публичных видео. Мы не планируем загружать, редактировать, удалять или комментировать видео от имени пользователей.


Предоставление доступа video для нашего приложения позволит нам эффективнее использовать контент из VK на нашем сайте.
Прошу рассмотреть возможность одобрения scope: 'video'.
Спасибо!
```

  
  
  
Пишите так чтобы ваш запрос ушел оператору, а не боту, добейтесь того чтобы вам ответил человек.  
Мне одобрили через неделю.  
  
[![otvet.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-11/scaled-1680-/JaRQ90NC8JwyndvN-otvet.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-11/JaRQ90NC8JwyndvN-otvet.jpg)  
  
  
Как разрешение одобрят, нужно нажать кнопку "авторизироваться в vk" в отдельной вкладке возле видеогалереи

[![vk31.jpg](https://docs.ivan345.com/uploads/images/gallery/2025-11/scaled-1680-/pxTTQSmbqiVUWZmV-vk31.jpg)](https://docs.ivan345.com/uploads/images/gallery/2025-11/pxTTQSmbqiVUWZmV-vk31.jpg)