# 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 class="table-block has-export-button"><div class="table-content not-end-of-paragraph" not-end-of-paragraph=""><table style="width: 100%;"><thead><tr><td style="width: 15.6055%;">Параметр</td><td style="width: 24.2933%;">По умолчанию</td><td style="width: 60.1668%;">Описание</td></tr></thead><tbody><tr><td style="width: 15.6055%;">**&amp;resource**</td><td style="width: 24.2933%;">ID текущего ресурса</td><td style="width: 60.1668%;">ID ресурса, из которого нужно вывести изображения. Используется, если `&parents` и `&resources` не заданы.</td></tr><tr><td style="width: 15.6055%;">**&amp;parents**</td><td style="width: 24.2933%;">`null`</td><td style="width: 60.1668%;">Список ID родительских ресурсов через запятую. Выбирает картинки из этих ресурсов и всех их дочерних. `0` — выборка со всего сайта.</td></tr><tr><td style="width: 15.6055%;">**&amp;resources**</td><td style="width: 24.2933%;">`null`</td><td style="width: 60.1668%;">Список ID ресурсов через запятую. ID с минусом (-) исключает ресурс. Имеет приоритет над `&parents`, если указаны положительные ID.</td></tr><tr><td style="width: 15.6055%;">**&amp;tplOuter**</td><td style="width: 24.2933%;">`...`</td><td style="width: 60.1668%;">Имя чанка-обертки для сложных галерей (например, каруселей).</td></tr><tr><td style="width: 15.6055%;">**&amp;tplThumb**</td><td style="width: 24.2933%;">`...`</td><td style="width: 60.1668%;">Имя чанка для элемента в ленте превью (используется вместе с `tplOuter`, **игнорируется в режиме Fenom**).</td></tr><tr><td style="width: 15.6055%;">**&amp;fenom**</td><td style="width: 24.2933%;">`0`</td><td style="width: 60.1668%;">Если установить в `1` и на сайте установлен `pdoTools`, сниппет будет работать в режиме Fenom. В этом режиме он не обрабатывает чанк `&tplThumb`, а передает в чанк `&tplOuter` сырой массив со всеми данными `{$files}`, который вы можете обработать в цикле `{foreach}`.</td></tr><tr><td style="width: 15.6055%;">**&amp;limit**</td><td style="width: 24.2933%;">0</td><td style="width: 60.1668%;">Ограничение на количество выводимых изображений. `0` — без ограничений.</td></tr><tr><td style="width: 15.6055%;">**&amp;offset**</td><td style="width: 24.2933%;">  
</td><td style="width: 60.1668%;">Пропуск результатов с начала выборки</td></tr><tr><td style="width: 15.6055%;">**&amp;sortby**</td><td style="width: 24.2933%;">position</td><td style="width: 60.1668%;">Поле для сортировки изображений. Можно сортировать и по дополнительным полям, например `extra_num` или `extra_date`.</td></tr><tr><td style="width: 15.6055%;">**&amp;sortdir**</td><td style="width: 24.2933%;">ASC</td><td style="width: 60.1668%;">Направление сортировки (ASC или DESC).</td></tr><tr><td style="width: 15.6055%;">**&amp;showInactive**</td><td style="width: 24.2933%;">0</td><td style="width: 60.1668%;">Если установить в `1`, будут выводиться также и выключенные в админке изображения.</td></tr><tr><td style="width: 15.6055%;">**&amp;where**</td><td style="width: 24.2933%;">`''`</td><td style="width: 60.1668%;">JSON-строка с дополнительными условиями выборки. Можно фильтровать и по доп-полям, например `{"extra_num:>":2000}`.</td></tr><tr><td style="width: 15.6055%;">**&amp;debug**</td><td style="width: 24.2933%;">0</td><td style="width: 60.1668%;">Если установить в `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]]`.
- `[[+group]]` - Группы изображения (несколько — через `||`)
- `[[+special]]` - Признак "особенный" (1/0)
- `[[+extra_text]]` - Дополнительное текстовое поле
- `[[+extra_text2]]` - Второе дополнительное текстовое поле
- `[[+extra_num]]` - Дополнительное числовое поле (удобно для сортировки/фильтра)
- `[[+extra_date]]` - Дополнительное поле даты (формат `ГГГГ-ММ-ДД 00:00:00`)

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

Начиная с версии **3.2.1** у каждого изображения есть универсальные поля для нестандартных задач, которые заполняются в окне редактирования (вкладка «Дополнительно»): `extra_text`, `extra_text2`, `extra_num`, `extra_date`. Они доступны в чанках как обычные плейсхолдеры. Названия этих полей в админке можно переопределить в системных настройках компонента (область «Доп. поля: изображения»).

Поле даты хранится в формате `datetime`, поэтому при необходимости форматируйте его выводным модификатором:

```
[[+extra_date:strtotime:date=`%d.%m.%Y`]]
```

Те же поля доступны и в сниппетах `Gallery3xVideos`, `Gallery3xFiles`, `Gallery3xEmbeds` и `Gallery3xMixed` — они выводятся автоматически.

сниппет Gallery3x поддерживает параметры `&return` и `&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"}`
]]
```

# Gallery3xEmbeds

Компонент `Gallery3x` начиная с версии **3.2.1** поставляется со сниппетом `[[!Gallery3xEmbeds]]`, который выводит на страницах сайта **встраиваемые объекты (embed)** — карты, виджеты, плееры и любой iframe-контент, добавленный во вкладке **«Embed G3x»** ресурса.

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

Каждый embed добавляется в админке в одном из двух режимов:

- **Ссылка** — вы вставляете ссылку (например, на Яндекс.Карты или Google Карты), компонент распознаёт её и **сам строит безопасный `<iframe>`**.
- **Код вставки** — вы вставляете готовый HTML-код встраивания (кнопка «Поделиться → Встроить» на сайте-источнике), он выводится как есть.

Сниппет отдаёт в чанк **уже готовый HTML** embed в плейсхолдере `[[+embed_html]]` с адаптивной обёрткой (ширина 100%, высота из поля «Высота», по умолчанию 400px).

---

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

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

<table id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9F%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB%D1%87%D0%B0%D0%BD%D0%B8" style="width: 100%;"><thead><tr><td style="width: 16%;">Параметр</td><td style="width: 24%;">По умолчанию</td><td style="width: 60%;">Описание</td></tr></thead><tbody><tr><td>**&amp;resource**</td><td>ID текущего ресурса</td><td>ID ресурса, из которого выводить embed. Используется, если `&parents` и `&resources` не заданы.</td></tr><tr><td>**&amp;parents**</td><td>`null`</td><td>Список ID родительских ресурсов через запятую. Выбирает embed из них и всех дочерних. `0` — со всего сайта.</td></tr><tr><td>**&amp;resources**</td><td>`null`</td><td>Список ID ресурсов через запятую. ID с минусом (-) исключает ресурс. Имеет приоритет над `&parents`.</td></tr><tr><td>**&amp;tplOuter**</td><td>`tpl.Gallery3x.Embed.outer`</td><td>Чанк-обёртка всего списка.</td></tr><tr><td>**&amp;tplItem**</td><td>`tpl.Gallery3x.Embed.item`</td><td>Чанк одного элемента (**игнорируется в режиме Fenom**).</td></tr><tr><td>**&amp;fenom**</td><td>`0`</td><td>Если `1` и установлен `pdoTools` — режим Fenom. Чанк `&tplItem` не используется, а в `&tplOuter` передаётся массив `{$embeds}` для обработки в `{foreach}`.</td></tr><tr><td>**&amp;group**</td><td>`''`</td><td>Фильтр по группе (можно несколько через запятую).</td></tr><tr><td>**&amp;limit**</td><td>`0`</td><td>Ограничение количества. `0` — без ограничений.</td></tr><tr><td>**&amp;offset**</td><td>`0`</td><td>Сдвиг выборки (для постраничного вывода).</td></tr><tr><td>**&amp;sortby**</td><td>`position`</td><td>Поле сортировки.</td></tr><tr><td>**&amp;sortdir**</td><td>`ASC`</td><td>Направление сортировки (ASC или DESC).</td></tr><tr><td>**&amp;showInactive**</td><td>`0`</td><td>Если `1` — выводятся и выключенные в админке embed.</td></tr><tr><td>**&amp;where**</td><td>`''`</td><td>JSON-строка с дополнительными условиями выборки.</td></tr><tr><td>**&amp;debug**</td><td>`0`</td><td>Если `1` — вместо вывода показывается массив подготовленных данных.</td></tr></tbody></table>

### Доступные плейсхолдеры

Сниппет передаёт в чанк **все поля** записи embed. Главный — `[[+embed_html]]` (готовый к выводу HTML).

- **`[[+embed_html]]`** — **готовый HTML** embed с адаптивной обёрткой (это и нужно выводить).
- `[[+id]]` — ID записи.
- `[[+title]]` — заголовок.
- `[[+description]]` — описание.
- `[[+mode]]` — режим: `url` или `code`.
- `[[+url]]` — исходная ссылка (режим «Ссылка»).
- `[[+code]]` — код вставки (режим «Код вставки»).
- `[[+provider]]` — провайдер (`yandex_map`, `google_map`).
- `[[+embed_id]]` — итоговый `src` для iframe (режим «Ссылка»).
- `[[+height]]` — высота в px (пусто = 400).
- `[[+thumbnail_url]]` — URL превью (если задано).
- `[[+group]]` — группы (через `||`).
- `[[+position]]`, `[[+active]]`, `[[+special]]` — позиция, активность, «особенный».
- `[[+extra_text]]`, `[[+extra_text2]]`, `[[+extra_num]]`, `[[+extra_date]]` — дополнительные поля.

### Примеры

```
[[!Gallery3xEmbeds]]
```

Вывести все embed текущего ресурса.

```
[[!Gallery3xEmbeds?
  &group=`maps`]]
```

Только embed из группы `maps`.

```
[[!Gallery3xEmbeds? &resource=`15`
  &limit=`3`]]
```

Три embed с ресурса №15.

```
[[!Gallery3xEmbeds? &fenom=`1` &tplOuter=`
  tpl.Gallery3x.Embed.outer.fenom`]]
```

Режим Fenom — обработка массива `{$embeds}` в цикле внутри чанка-обёртки.

```
[[!Gallery3xEmbeds? &debug=`1`]]
```

Отладка — показывает все подготовленные данные.

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

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

Специальный плагин один раз подготавливает все данные и делает их доступными в виде простых плейсхолдеров, таких как `[[+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)

# Gallery3x: вставка галерей в визуальный редактор

# Вставка галерей в визуальный редактор

Компонент Gallery3x добавляет в визуальный редактор MODX кнопку **«Вставить из галереи»**. Она открывает окно выбора изображений текущего ресурса и вставляет в текст готовый вызов сниппета (или тег `<img>`) с ID выбранных фото. В зависимости от выбранного «вида вывода» в вызов подставляются разные чанки — сетка Fancybox, карусель, простые миниатюры и т.д.

## Поддерживаемые редакторы

- **CKEditor** — аддон `ckeditor` 1.4.x (CKEditor 4);
- **TinyMCE RTE** — аддон `tinymcerte` 3.x (TinyMCE 6).

Адаптер выбирается автоматически: скрипты Gallery3x сами определяют, какой редактор загружен на странице, и молча отключаются, если «их» редактора нет. Настройки самих аддонов CKEditor / TinyMCE RTE менять **не нужно** — кнопка регистрируется программно.

## Включение и настройка

Все настройки находятся в системных настройках MODX, пространство имён `gallery3x`, раздел «Визуальный редактор (RTE)».

<table border="1" cellpadding="6" cellspacing="0" id="bkmrk-%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-%D0%9F%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB%D1%87%D0%B0%D0%BD"><thead><tr><th>Настройка</th><th>По умолчанию</th><th>Описание</th></tr></thead><tbody><tr><td>`gallery3x.rte_enable`</td><td>Нет</td><td>Включает кнопку галереи в визуальном редакторе. Главный выключатель.</td></tr><tr><td>`gallery3x.rte_templates`</td><td>пусто</td><td>На каких шаблонах показывать кнопку:  
• пусто — использовать список из `gallery3x.templates` (там же, где вкладка галереи);  
• `*` — на всех шаблонах;  
• `5,10` — только на шаблонах с этими ID.</td></tr><tr><td>`gallery3x.rte_views`</td><td>пусто</td><td>JSON-массив «видов вывода» для окна вставки. Пусто — стандартный набор (см. ниже).</td></tr></tbody></table>

После включения настройки откройте ресурс с визуальным редактором — кнопка появится в тулбаре (в CKEditor — отдельной группой в конце, в TinyMCE — в конце первого ряда). Если кнопки нет — обновите страницу менеджера со сбросом кэша браузера (Ctrl+F5).

## Окно выбора изображений

По клику на кнопку открывается окно со всеми изображениями текущего ресурса:

- **Фильтр по группе** — слева вверху; кнопка «Сбросить» возвращает все фото;
- **Миниатюры** — клик выбирает/снимает фото (Ctrl не нужен), выбор работает и между страницами пагинации;
- **Порядок кликов запоминается** — фото будут выведены на странице именно в той последовательности, в которой вы их выбирали;
- **Счётчик «Выбрано: N»** и кнопка «Сбросить выбор» — справа вверху;
- внизу — параметры вставки (см. следующий раздел) и кнопки «Вставить» / «Отмена».

## Режимы вставки

<table border="1" cellpadding="6" cellspacing="0" id="bkmrk-%D0%A0%D0%B5%D0%B6%D0%B8%D0%BC-%28%C2%AB%D0%A7%D1%82%D0%BE-%D0%B2%D1%81%D1%82%D0%B0%D0%B2%D0%B8%D1%82%D1%8C"><thead><tr><th>Режим («Что вставить»)</th><th>Что попадёт в текст</th><th>Поведение</th></tr></thead><tbody><tr><td>Выбранные фото</td><td>`[[!Gallery3x? &ids=`17,5,42` &tplOuter=`...` &tplThumb=`...`]]`</td><td>Выводятся ровно эти фото, в порядке кликов. Состав фиксированный.</td></tr><tr><td>Всю группу (динамически)</td><td>`[[!Gallery3x? &group=`Имя группы` &resource=`12` &tplOuter=`...`]]`</td><td>Выводятся все фото группы. Если позже в группу добавить фото — они появятся на странице автоматически.</td></tr><tr><td>Все фото ресурса</td><td>`[[!Gallery3x? &resource=`12` &tplOuter=`...`]]`</td><td>Вся галерея ресурса, тоже динамически.</td></tr><tr><td>Вид «Одиночное фото (тег img)»</td><td>`<img src="[[g3xGetImage? &input=`17` &options=`medium`]]" alt="...">`</td><td>На каждое выбранное фото вставляется отдельный `<img>`. Размер выбирается в поле «Размер фото» (thumb / small / medium / large / original). Адрес картинки вычисляется по ID при выводе страницы, поэтому переживает перегенерацию превью.</td></tr></tbody></table>

Флажок **«Некэшированный вызов»** (включён по умолчанию) вставляет тег как `[[!Gallery3x?...]]`. Для одиночных фото вызов всегда кэшированный — это безопасно и быстрее.

## Виды вывода

«Вид вывода» определяет, какая пара чанков подставится в вызов сниппета. Стандартный набор:

<table border="1" cellpadding="6" cellspacing="0" id="bkmrk-%D0%92%D0%B8%D0%B4-tplouter-tplthum"><thead><tr><th>Вид</th><th>tplOuter</th><th>tplThumb</th></tr></thead><tbody><tr><td>Fancybox: сетка</td><td>`tpl.Gallery3x.Fancybox.GridOuter`</td><td>`tpl.Gallery3x.Fancybox.GridItem`</td></tr><tr><td>Fancybox: фото + миниатюры</td><td>`tpl.Gallery3x.Fancybox.outer`</td><td>`tpl.Gallery3x.Fancybox.thumbItem`</td></tr><tr><td>Карусель (lightGallery)</td><td>`tpl.Gallery3x.carousel.outer`</td><td>`tpl.Gallery3x.carousel.item`</td></tr><tr><td>Простые миниатюры</td><td>`tpl.Gallery3x.static_thumbnails.outer`</td><td>`tpl.Gallery3x.static_thumbnails`</td></tr><tr><td>Одиночное фото (тег img)</td><td colspan="2">специальный вид — вставляет `<img>`, чанки не используются</td></tr></tbody></table>

### Свои виды вывода (gallery3x.rte\_views)

Набор видов задаётся JSON-массивом в настройке `gallery3x.rte_views`. Каждый элемент массива — один пункт выпадающего списка «Вид вывода» в окне вставки.

**Важно знать перед настройкой:**

- Настройка **заменяет весь набор целиком**, а не дополняет его. Если стандартные виды нужны — включите их в JSON тоже (готовый блок — в примере 1).
- Порядок элементов в JSON = порядок в выпадающем списке; первый элемент выбран по умолчанию. Вид «Одиночное фото (тег img)» добавляется в конец списка всегда автоматически.
- Вид «зашивается» в тег при вставке. Изменение `gallery3x.rte_views` влияет только на будущие вставки — уже вставленные в контент теги не изменятся (но их можно править руками прямо в тексте).
- После изменения настройки перезагрузите страницу редактирования ресурса — конфиг читается при её открытии.
- Кавычки внутри значений JSON экранируются как `\"` (см. пример 4).

<table border="1" cellpadding="6" cellspacing="0" id="bkmrk-%D0%9F%D0%BE%D0%BB%D0%B5-%D0%9E%D0%B1%D1%8F%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5-%D0%9E%D0%BF"><thead><tr><th>Поле</th><th>Обязательное</th><th>Описание</th></tr></thead><tbody><tr><td>`key`</td><td>да</td><td>Уникальный ключ вида (латиницей, без пробелов).</td></tr><tr><td>`label`</td><td>да</td><td>Название в выпадающем списке окна вставки.</td></tr><tr><td>`tplOuter`</td><td>да</td><td>Чанк-обёртка, подставится в `&tplOuter`.</td></tr><tr><td>`tplThumb`</td><td>обычно да</td><td>Чанк элемента, подставится в `&tplThumb`. Можно опустить, если обёртка сама перебирает файлы (Fenom/@INLINE, см. пример 6).</td></tr><tr><td>`snippet`</td><td>нет</td><td>Имя вызываемого сниппета. По умолчанию `Gallery3x` (пример 5).</td></tr><tr><td>`fenom`</td><td>нет</td><td>`true` — добавить в вызов `&fenom=`1`` (чанки в синтаксисе Fenom, нужен pdoTools).</td></tr><tr><td>`extra`</td><td>нет</td><td>Строка с любыми дополнительными параметрами сниппета, добавляется в конец вызова как есть: `&limit`, `&offset`, `&sortby`, `&sortdir`, `&where`, `&showInactive` и т.д.</td></tr></tbody></table>

#### Пример 1. Стандартный набор + свой вид

Самый частый случай: оставить всё как было и добавить один свой вид. Ниже — полный JSON стандартного набора, к которому в конец добавлен вид «Моя сетка» на собственных чанках:

```
[
  {"key": "fancybox_grid", "label": "Fancybox: сетка", "tplOuter": "tpl.Gallery3x.Fancybox.GridOuter", "tplThumb": "tpl.Gallery3x.Fancybox.GridItem"},
  {"key": "fancybox", "label": "Fancybox: фото + миниатюры", "tplOuter": "tpl.Gallery3x.Fancybox.outer", "tplThumb": "tpl.Gallery3x.Fancybox.thumbItem"},
  {"key": "carousel", "label": "Карусель (lightGallery)", "tplOuter": "tpl.Gallery3x.carousel.outer", "tplThumb": "tpl.Gallery3x.carousel.item"},
  {"key": "static", "label": "Простые миниатюры", "tplOuter": "tpl.Gallery3x.static_thumbnails.outer", "tplThumb": "tpl.Gallery3x.static_thumbnails"},
  {"key": "my_grid", "label": "Моя сетка", "tplOuter": "tpl.My.GridOuter", "tplThumb": "tpl.My.GridItem"}
]
```

При выборе «Моя сетка» и трёх фото в текст вставится:

```
[[!Gallery3x? &ids=`17,5,42` &tplOuter=`tpl.My.GridOuter` &tplThumb=`tpl.My.GridItem`]]
```

#### Пример 2. Fenom-виды на готовых чанках компонента

В составе Gallery3x уже есть Fenom-варианты чанков Fancybox — их можно подключить отдельными видами (нужен pdoTools):

```
[
  {"key": "fancybox_grid", "label": "Fancybox: сетка", "tplOuter": "tpl.Gallery3x.Fancybox.GridOuter", "tplThumb": "tpl.Gallery3x.Fancybox.GridItem"},
  {"key": "fb_grid_fenom", "label": "Fancybox: сетка (Fenom)", "tplOuter": "tpl.Gallery3x.Fancybox.GridOuter.fenom", "tplThumb": "tpl.Gallery3x.Fancybox.GridItem.fenom", "fenom": true}
]
```

Что вставится:

```
[[!Gallery3x? &ids=`17,5,42` &tplOuter=`tpl.Gallery3x.Fancybox.GridOuter.fenom` &tplThumb=`tpl.Gallery3x.Fancybox.GridItem.fenom` &fenom=`1`]]
```

#### Пример 3. Дополнительные параметры через extra: лимит и сортировка

Поле `extra` — точка расширения: любые параметры сниппета `Gallery3x` допишутся в конец вызова. Вид «Последние 6 фото» (удобен с режимами «Вся группа» / «Все фото ресурса» — лимит и сортировка применятся к динамической выборке):

```
[
  {"key": "last6", "label": "Последние 6 фото", "tplOuter": "tpl.Gallery3x.Fancybox.GridOuter", "tplThumb": "tpl.Gallery3x.Fancybox.GridItem", "extra": "&limit=`6` &sortby=`createdon` &sortdir=`DESC`"}
]
```

Что вставится (режим «Все фото ресурса»):

```
[[!Gallery3x? &resource=`12` &tplOuter=`tpl.Gallery3x.Fancybox.GridOuter` &tplThumb=`tpl.Gallery3x.Fancybox.GridItem` &limit=`6` &sortby=`createdon` &sortdir=`DESC`]]
```

#### Пример 4. Фильтр по полям через &amp;where (экранирование кавычек)

Параметр `&where` принимает JSON — внутри значения настройки его кавычки надо экранировать обратной косой: `\"`. Вид «Только особенные фото» (поле `special`, звёздочка в галерее):

```
[
  {"key": "special", "label": "Только особенные фото", "tplOuter": "tpl.Gallery3x.Fancybox.GridOuter", "tplThumb": "tpl.Gallery3x.Fancybox.GridItem", "extra": "&where=`{\"special\":1}`"}
]
```

Аналогично можно фильтровать по любым полям изображения: `{\"extra_num\":2024}`, `{\"description:!=\":\"\"}` и т.д.

#### Пример 5. Свой сниппет вместо Gallery3x

Если у вас есть сниппет-обёртка со своей логикой (свои дефолты, кэширование, обработка), укажите его в поле `snippet` — кнопка будет вставлять вызов именно его, передавая те же параметры (`&ids` / `&group` / `&resource` и чанки):

```
[
  {"key": "my_slider", "label": "Слайдер (свой сниппет)", "snippet": "MySlider", "tplOuter": "tpl.MySlider.outer", "tplThumb": "tpl.MySlider.item", "extra": "&autoplay=`1` &interval=`5000`"}
]
```

Что вставится:

```
[[!MySlider? &ids=`17,5,42` &tplOuter=`tpl.MySlider.outer` &tplThumb=`tpl.MySlider.item` &autoplay=`1` &interval=`5000`]]
```

#### Пример 6. @INLINE-шаблон без отдельного чанка (продвинутый, нужен pdoTools)

С `"fenom": true` обёртку можно задать прямо строкой `@INLINE` — без создания чанка. Внутри доступен массив `$files` (все поля фото + URL всех размеров: `small_url`, `medium_url`, `large_url`, `original_url`). `tplThumb` в этом случае не нужен:

```
[
  {"key": "inline_row", "label": "Ряд миниатюр (inline)", "fenom": true, "tplOuter": "@INLINE {foreach $files as $f}<a href=\"{$f.original_url}\"><img src=\"{$f.small_url}\" alt=\"{$f.alt}\"></a>{/foreach}"}
]
```

Такой вид удобен для мелких служебных вставок, когда заводить чанк избыточно. Для чего-то сложнее пары строк лучше всё же создать чанк — его проще править и переиспользовать.

#### Типовые ошибки

- Забыли включить стандартные виды в свой JSON — в списке останутся только ваши (это не поломка, но часто неожиданность).
- Невалидный JSON (лишняя запятая, неэкранированные кавычки) — компонент откатится на стандартный набор и запишет предупреждение в журнал ошибок MODX (Управление → Журнал ошибок).
- Опечатка в имени чанка — вызов вставится, но на странице галерея не выведется; проверьте имена в дереве «Элементы».
- Fenom-чанк без `"fenom": true` (или без установленного pdoTools) — на странице будет сырой текст шаблона вместо галереи.

## Изменения в сниппетах

### Gallery3x: параметр &amp;ids

`&ids=`17,5,42`` — вывод конкретных изображений по их ID (именно этот параметр использует режим «Выбранные фото»).

- ID изображения уникален на весь сайт и сам однозначно определяет фото, поэтому параметры выбора по ресурсам (`&resource` / `&resources` / `&parents`) в вызове с `&ids` не нужны и не учитываются. Иначе фото, прикреплённое к другому ресурсу, молча пропадало бы из вывода.
- Порядок вывода равен порядку перечисления ID; его можно переопределить обычным `&sortby`.
- Фильтр активности (`active = 1`), а также `&where`, `&limit`, `&showInactive` действуют как обычно.
- **Обратная совместимость полная:** на вызовы без `&ids` изменение не влияет — выполняется прежний код выборки по ресурсам.

### g3xGetImage: размер original

`[[g3xGetImage? &input=`17` &options=`original`]]` теперь возвращает URL оригинального файла (раньше были доступны только размеры превью: thumb, small, medium, large).

## Возможные проблемы и решения

<table border="1" cellpadding="6" cellspacing="0" id="bkmrk-%D0%A1%D0%B8%D0%BC%D0%BF%D1%82%D0%BE%D0%BC-%D0%9F%D1%80%D0%B8%D1%87%D0%B8%D0%BD%D0%B0-%D0%B8-%D1%80%D0%B5"><thead><tr><th>Симптом</th><th>Причина и решение</th></tr></thead><tbody><tr><td>Кнопки нет в тулбаре</td><td>Проверьте: `gallery3x.rte_enable` = Да; шаблон ресурса входит в `gallery3x.rte_templates` (или `gallery3x.templates`, если первая пуста); страница менеджера обновлена с Ctrl+F5.</td></tr><tr><td>Кнопка без иконки (пустой квадрат)</td><td>Браузер держит старый CSS/JS — обновите менеджер с Ctrl+F5.</td></tr><tr><td>CKEditor: кнопки нет при нестандартном тулбаре</td><td>Если тулбар CKEditor задан нестандартной конфигурацией, добавьте кнопку `Gallery3x` в неё вручную.</td></tr><tr><td>TinyMCE: в сохранённом тексте `&amp;` вместо `&` внутри тега MODX</td><td>Это нормально: MODX-парсер понимает `&amp;` в параметрах тегов, вывод работает.</td></tr><tr><td>TinyMCE искажает `src` у одиночного фото</td><td>Зависит от настроек конвертации URL аддона — установите `tinymcerte.relative_urls` = Нет.</td></tr><tr><td>Галерея не выводится на странице</td><td>Убедитесь, что чанки выбранного вида существуют, а вызов вставлен некэшированным (`[[!...]]`), если содержимое должно обновляться.</td></tr></tbody></table>

## Техническая справка

- `core/components/gallery3x/elements/plugins/plugin.gallery3x_rte.php` — MODX-плагин (событие `OnDocFormPrerender`): проверяет настройки и шаблон, передаёт конфиг в JS, подключает скрипты и стили;
- `assets/components/gallery3x/js/mgr/rte/gallery3x.rte.picker.js` — окно выбора (ExtJS), редактор-независимое ядро: `Gallery3x.rte.openPicker(callback)`;
- `assets/components/gallery3x/js/mgr/rte/gallery3x.rte.ckeditor.js` — адаптер CKEditor 4: регистрирует плагин и кнопку через `CKEDITOR.plugins.add` + событие `instanceCreated`/`configLoaded`;
- `assets/components/gallery3x/js/mgr/rte/gallery3x.rte.tinymce.js` — адаптер TinyMCE 6: регистрирует плагин через `tinymce.PluginManager.add` и дописывает `gallery3x` в `plugins`/`toolbar1` объекта `TinyMCERTE.editorConfig` до вызова `tinymce.init()`;
- `assets/components/gallery3x/css/mgr/rte.picker.css` — стили окна и иконка кнопки CKEditor;
- `assets/components/gallery3x/gallery3x-icon.svg` — фирменная иконка Gallery3x (мастер-копия).

Данные окно берёт через штатный коннектор компонента (`connector.php`, процессоры `File\GetList` и процессор групп из `gallery3x.groups_processor`) — работает только в контексте менеджера с активной сессией.

Чтобы подключить другой редактор, достаточно написать новый адаптер, который по своему событию вызывает `Gallery3x.rte.openPicker(function (html) { /* вставка html в редактор */ })`.