=== WP PWA Generator ===
Contributors: <ЛОГИН НА WORDPRESS.ORG — ЗАПОЛНИТЬ ПЕРЕД ПУБЛИКАЦИЕЙ>
Tags: pwa, progressive-web-app, offline, push-notifications, manifest
Requires at least: 5.8
Tested up to: 7.0.4
Requires PHP: 7.4
Stable tag: 0.2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

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

== Description ==

Ваш сайт на WordPress уже есть. Приложения у него нет — а посетитель хочет
поставить иконку на домашний экран, открывать её без адресной строки и читать
вас в метро.

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

Плагин делает это сам. После активации в админке появляется раздел **PWA** с
девятью вкладками настроек. Плагин создаёт на сайте папку — по умолчанию
`ваш-сайт.ru/app/`, а если в корень писать нельзя, `wp-content/uploads/pwa-app/`
— и кладёт туда самостоятельное приложение: `index.html`, service worker,
`manifest.webmanifest`, полный набор иконок и splash-экранов, стили и скрипты.
Содержимое приложение берёт с этого же сайта через WP REST API.

Посетитель заходит на `ваш-сайт.ru/app/`, браузер предлагает установить, иконка
появляется на домашнем экране.

= Первое приложение появляется само =

Сразу после активации плагин собирает приложение на умолчаниях: имя и описание —
из настроек сайта, иконка — из логотипа сайта или нарисованная из первой буквы
названия. Вы открываете админку и обнаруживаете работающее приложение, а не
пустой экран с кнопкой. Кнопка «Собрать приложение» нужна для пересборки после
правок.

= Что получает посетитель =

* лента материалов сайта с подгрузкой по мере прокрутки;
* экран материала: заголовок, картинка, текст, автор, дата, рубрики;
* выбранные вами страницы сайта в меню приложения;
* поиск по сайту;
* рубрики и метки как фильтр ленты;
* чтение офлайн: то, что уже открывалось, открывается без сети;
* понятный экран «Нет сети» вместо белого пятна;
* приватный и парольный контент посетителю не показывается — приложение берёт
  только то, что REST отдаёт неавторизованному гостю.

= Шесть возможностей, которые включаются галочкой =

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

1. **Уведомления.** Web Push на ваших собственных ключах VAPID. Без Firebase,
   без посредников, без чужого аккаунта. Форма отправки, автоотправка при выходе
   новой записи, отчёт «доставлено / отказано / протухло», очередь партиями,
   центр уведомлений внутри приложения.
2. **Расширенный офлайн.** Стратегия и срок хранения на каждый вид ресурса,
   лимиты по числу файлов и по объёму, список адресов для предзагрузки, кнопка
   «Сохранить для чтения» у материала и раздел «Сохранённое» в приложении.
3. **Биометрия.** Две разные вещи, включаются раздельно: замок приложения
   (открыть приложение отпечатком или лицом) и вход в аккаунт сайта по passkey,
   без пароля. Вход паролем остаётся всегда.
4. **Геолокация и карты.** Раздел «Рядом» — материалы, отсортированные по
   расстоянию; карта на тайлах OpenStreetMap, без ключей и платных сервисов;
   поля широты и долготы в редакторе записи.
5. **Отложенные действия.** Действие, сделанное без сети, кладётся в очередь на
   устройстве и уезжает, когда сеть появится. Один раз, а не дважды.
6. **Иконка нейросетью.** Опишите иконку словами — её нарисуют. Нужен свой
   ключ, платный; как его получить, написано ниже в вопросах.

= Иконка =

Загрузите свою картинку — из неё сами нарежутся все размеры, которых требуют
платформы: 48, 72, 96, 128, 144, 152, 167, 180, 192, 256, 384, 512, отдельная
maskable, apple-touch и favicon. Плюс девять splash-экранов под актуальные
экраны iPhone и iPad.

Картинки нет — плагин нарисует иконку сам: из логотипа сайта, а если и его нет —
из первой буквы названия на фоне вашего фирменного цвета. Предпросмотр
показывает, как иконка будет выглядеть круглой, квадратной и maskable с
безопасной зоной, — до сборки, а не после.

= Ни одной зависимости =

В плагине нет composer, нет npm, нет `vendor/`, нет `node_modules/`, нет ни
одного обращения к CDN и ни одной чужой JavaScript-библиотеки в собранном
приложении. Всё построено на функциях самого PHP и API WordPress.

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

= Что нужно от сервера =

* PHP 7.4 или новее;
* WordPress 5.8 или новее;
* **HTTPS** — без него ни один браузер не установит приложение и не включит
  service worker. Сборка без HTTPS заблокирована, и плагин говорит об этом сразу,
  а не после;
* расширение **GD** или **Imagick** — чтобы нарезать иконки;
* расширение **openssl** — только для уведомлений и входа по ключу. Нет его —
  недоступны эти две возможности, остальное приложение работает;
* право записи в корень сайта или в папку загрузок.

Всё это плагин проверяет сам и показывает на вкладке «Состояние» словами, а не
кодами ошибок.

= Ваши данные остаются вашими =

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

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

== Installation ==

1. Скопируйте папку `wp-pwa-generator` в `wp-content/plugins/` или установите
   zip обычным способом: **Плагины → Добавить новый → Загрузить плагин**.
2. Активируйте плагин. Ничего больше делать не нужно: ни `composer install`,
   ни `npm install`, ни сборки.
3. Плагин соберёт первое приложение сам. Откройте **PWA → Состояние** — там
   ссылка на него.
4. Пройдите вкладки **Основное**, **Внешний вид**, **Иконка** и **Контент**,
   поправьте что хотите и нажмите **Собрать приложение**.

Если сборка не удалась, на вкладке «Состояние» написано, на каком из семи шагов
и почему. Самые частые причины и что с ними делать — ниже в вопросах.

**Обновление.** Обновляйте плагин обычным способом и пересоберите приложение
после обновления: файлы оболочки в папке приложения заменяются только сборкой.

**Удаление.** По умолчанию удаление плагина ничего не уносит: ни настройки, ни
подписки, ни собранную папку. Если хотите, чтобы уносило, включите
**Дополнительно → «Удалить все данные при удалении плагина»** до того, как
удалите плагин.

== Frequently Asked Questions ==

= На iPhone нет кнопки «Установить». Плагин сломан? =

Нет. Кнопки «Установить» на iPhone и iPad не бывает вообще — Safari её не
показывает ни одному сайту в мире. Единственный путь установки на iOS такой:

1. открыть приложение в **Safari** (в Chrome на iPhone это не работает);
2. нажать кнопку **«Поделиться»** — квадрат со стрелкой вверх;
3. пролистать список вниз до **«На экран „Домой“»**;
4. нажать **«Добавить»**.

Приложение само подсказывает это посетителю, зашедшему с iPhone или iPad:
«Чтобы установить: „Поделиться“ → „На экран „Домой““». Подсказка показывается
один раз, потом больше не появляется.

На Android и на компьютере всё иначе: там браузер сам предлагает установку, и в
приложении есть кнопка **«Установить»**.

= Где взять ключ для рисования иконки нейросетью? =

Ключ платный и принадлежит вам, а не плагину. Получить его можно здесь:

**https://aitunnel.ru?r=2049**

Заведите там аккаунт, пополните баланс, скопируйте ключ и вставьте его на
вкладке **Дополнительно** в поле «Ключ API». Там же выберите модель: по
умолчанию стоит самая дешёвая, около 0,41 ₽ за картинку.

Дальше — вкладка **Иконка**: опишите иконку словами и нажмите «Нарисовать
варианты». Понравившийся вариант станет источником иконки приложения.

Пока ключа нет, кнопка просто неактивна и подписана «Нужен API-ключ» —
ничего не ломается.

Подробнее — в инструкции, раздел «Иконка нейросетью».

= Тратит ли плагин мой ключ, когда я просто открываю настройки? =

Нет. Деньги списываются ровно на одно действие: нажатие кнопки «Нарисовать
варианты». Предпросмотр иконки, отчёт об источниках картинки и открытие любой
вкладки к сервису не обращаются вообще. Кнопка «Проверить ключ» спрашивает у
сервиса список моделей — это бесплатно и ничего не рисует.

= Куда девается мой ключ? =

Никуда. Он лежит в базе вашего сайта в отдельной строке, которая не грузится на
каждом запросе. В интерфейсе вместо него точки. В экспорт настроек он не
попадает. В собранное приложение не попадает. В журнал сборок не попадает.

Одна оговорка, и она же написана в админке под кнопкой «Импорт из файла» ровно
этими словами: «Файл настроек может нести ключ, если вы вписали его туда руками,
— не пересылайте такой файл.» То есть: экспорт секретов не пишет никогда, но
отредактированный вручную файл импорт примет. Это сделано намеренно, чтобы
переносить настройки между своими сайтами.

= Приложение не собирается. Что делать? =

Откройте **PWA → Состояние**. Там журнал последних десяти сборок: время, итог,
шаг, на котором всё остановилось, и что произошло. Шагов семь: подготовка папки,
иконки, манифест, service worker, оболочка, конфигурация, публикация.

Самые частые причины:

* **Нет HTTPS.** Кнопка сборки заблокирована намеренно: без сертификата
  приложение не установится и service worker не включится. Попросите у хостинга
  сертификат — сейчас он обычно бесплатный.
* **Некуда писать.** Ни в корень сайта, ни в папку загрузок нельзя писать.
  Проверьте права на папки или выберите размещение «в каталоге загрузок» на
  вкладке «Основное».
* **Нет GD и Imagick.** Иконки нечем нарезать. На вкладке «Состояние» написано,
  какое расширение просить у хостинга.
* **Папка занята чужими файлами.** Плагин не затирает чужое: он останавливается
  и спрашивает подтверждение. Подтвердите замену или задайте другое имя папки.
* **Картинка иконки пропала из медиатеки.** Выберите её заново на вкладке
  «Иконка».

Пока сборка не прошла, посетители продолжают видеть предыдущее приложение:
плагин собирает во временную папку и переключает её на место в последнем шаге.

= Нужен ли мне отдельный сервер для уведомлений? =

Нет. Уведомления работают на ваших собственных ключах VAPID, которые генерирует
сам плагин, и уходят с вашего сайта прямо в push-сервис браузера. Ни Firebase,
ни OneSignal, ни чьего-либо ещё аккаунта не требуется.

Что нужно: HTTPS, расширение `openssl` на сервере и одно нажатие кнопки
«Создать ключи» на вкладке «Уведомления».

**Пару ключей нельзя терять.** Все подписки посетителей привязаны к ней. Если
пересоздать ключи, все существующие подписки перестанут работать, и каждому
посетителю придётся подписываться заново. Поэтому кнопка «Пересоздать ключи»
требует отдельной отметки.

= Что делает галочка «удалить все данные при удалении плагина»? =

Ровно то, что написано, и это единственный способ что-либо потерять. При
включённой галочке удаление плагина уносит:

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

Это необратимо. По умолчанию галочка **выключена**: удаление плагина не должно
уносить с собой ваши настройки и подписки ваших читателей.

= Приложение не обновилось после того, как я поменял настройки =

Сохранение настроек помечает сборку устаревшей и показывает баннер
«Настройки изменились — пересоберите». Нажмите «Собрать приложение».

Хотите, чтобы пересборка шла сама, — на вкладке «Основное» есть галочка
«пересобирать автоматически при изменении настроек», и отдельная — пересобирать
раз в сутки.

= У посетителя открыта старая версия приложения =

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

= Можно ли собрать приложение из консоли? =

Да, если на сервере есть WP-CLI:

* `wp pwa build` — собрать; `wp pwa build --force` — собрать даже тогда, когда
  сайт не отвечает условиям установки;
* `wp pwa status` — где лежит приложение, свежее ли оно, журнал сборок;
* `wp pwa clean` — удалить папку приложения. Чужую папку команда не тронет.

= У меня мультисайт =

У каждого сайта сети своё приложение, своя папка и свои настройки. Сайты сети
друг другу не мешают.

= Работает ли это с моей темой? =

Приложение — отдельная папка со своей вёрсткой, темы сайта оно не касается
вовсе. Единственное место, где плагин появляется на самом сайте, — необязательный
баннер «У этого сайта есть приложение», и он выключен по умолчанию.

= У меня уже стоит другой PWA-плагин =

Плагин это заметит и предупредит жёлтым уведомлением с именем конкурента. Два
service worker на одном сайте мешают друг другу — оставьте один плагин.

== Screenshots ==

**Скриншотов в этой поставке нет.** Их ещё не сняли, а рисовать картинки
интерфейса вместо снимков — значит показать не то, что есть. Ниже описано, что
должно быть на каждом снимке; их надо снять на живом сайте до публикации в
каталоге и положить рядом файлами `screenshot-1.png` … `screenshot-6.png`.

1. Вкладка «Состояние»: карточка последней сборки со ссылкой на приложение,
   список проверок (HTTPS, права на запись, GD/Imagick, openssl, манифест,
   service worker, иконки) и кнопка «Собрать приложение».
2. Идущая сборка: полоса прогресса и подпись текущего шага из семи.
3. Вкладка «Иконка»: предпросмотр в трёх видах — круглом, квадратном и maskable
   с безопасной зоной — и выбор источника картинки.
4. Вкладка «Возможности»: пять переключателей, один включён и раскрыл свои
   настройки прямо под собой.
5. Собранное приложение на телефоне: лента материалов и нижняя навигация.
6. Приложение офлайн: полоса «Нет сети. Показываем то, что успели сохранить.»
   над закэшированной лентой.

== Changelog ==

= 0.2.0 =

* Новый раздел «Продвижение» — пять способов рассказать посетителям, что у
  сайта есть приложение. Все выключены по умолчанию: блок с кнопкой установки
  и инструкциями для iPhone, Android и компьютера — шорткодом `[wppwa_app]`
  или блоком редактора; готовая страница «Как установить приложение»; черновик
  новости-анонса; QR-код на приложение, нарисованный на вашем же сайте, без
  обращения к чужим сервисам; пункт меню, ведущий на приложение. Плагин ничего
  не создаёт и не публикует сам: страница и запись появляются по вашей кнопке
  и остаются черновиками, пока вы их не опубликуете.
  **Созданные страница и запись остаются после удаления плагина** — это
  содержимое сайта, а не плагина.
* Сборка больше не зависит от того, есть ли на сервере шрифт: буква для иконки
  ищется теперь и среди шрифтов самого WordPress, а если шрифта нет нигде —
  вместо буквы рисуется простой знак. Плагин работает и на тех хостингах, где
  раньше не мог собрать приложение вовсе.

= 0.1.3 =

* Ссылка «Проверить обновление» переехала на своё место — в строку под
  описанием плагина, сразу после автора: «Версия 0.1.3 | Автор: Александр
  Холодов | Проверить обновление | Подробнее».
* Имя автора в той же строке стало ссылкой на его сайт.

= 0.1.2 =

* Проверить, вышла ли новая версия плагина, стало где нажать: ссылка
  «Проверить обновление» в строке плагина на экране «Плагины» и кнопка на
  вкладке «Состояние». Родная кнопка WordPress «Проверить снова» на экране
  «Обновления» теперь тоже доходит до плагина — раньше новая версия
  появлялась в списке не сразу.
* Блок услуг автора переехал в правую колонку вкладки «Состояние». На узком
  экране он уходит вниз.

= 0.1.1 =

* Сборка приложения больше не спрашивает про чужие файлы в собственной папке, а
  ежедневная пересборка по расписанию снова доходит до конца.
* Значок сайта в формате `.ico` больше не роняет сборку: плагин берёт следующую
  картинку и говорит, какая нужна — исходный логотип от 512 точек.
* Две сборки, запущенные одновременно, больше не мешают друг другу: вторая
  останавливается и сообщает, что первая ещё идёт.
* На вкладке «Состояние» появился блок услуг автора.

= 0.1.0 =

Первый выпуск.

* Сборка приложения в отдельную папку одной кнопкой, семью короткими шагами,
  с переключением в конце — провал на любом шаге оставляет старое приложение
  нетронутым.
* Первая сборка происходит сама, сразу после активации.
* Девять вкладок настроек: Основное, Внешний вид, Иконка, Контент, Офлайн,
  Уведомления, Возможности, Дополнительно, Состояние.
* Манифест, service worker, полный набор иконок и девять splash-экранов.
* Оболочка приложения: лента, материал, страницы, поиск, рубрики, офлайн.
* Иконка из загруженной картинки, из логотипа сайта, из первой буквы названия
  или нарисованная нейросетью по вашему ключу.
* Уведомления Web Push на своих ключах VAPID, без посредников.
* Расширенный офлайн: стратегии, сроки, лимиты, «Сохранённое».
* Биометрия: замок приложения и вход по passkey.
* Геолокация: раздел «Рядом» и карта на тайлах OpenStreetMap.
* Отложенные действия: очередь на устройстве и отправка при появлении сети.
* Экспорт и импорт настроек, журнал последних десяти сборок, баннер приложения
  на сайте, команды WP-CLI `wp pwa build`, `wp pwa status`, `wp pwa clean`.
* Ни одной зависимости: ни composer, ни npm, ни CDN.

**Честно о проверке.** Код на JavaScript покрыт тестами, и они проходят. Код на
PHP тоже покрыт тестами: писались они на машине без PHP, но прогнаны на живом
сервере — WordPress 7.0.4, PHP 8.3.6 — и там зелёные. Команда:
`php tests/php/run.php`. Подробнее — в `README.md` репозитория.

== Upgrade Notice ==

= 0.2.0 =
Новый раздел «Продвижение»: блок с кнопкой установки, готовая страница «Как
установить приложение», черновик анонса, QR-код и пункт меню — всё выключено
по умолчанию и ничего не публикуется без вас. Сборка приложения больше не
зависит от того, есть ли на сервере шрифт.

= 0.1.3 =
Ссылка «Проверить обновление» переехала в строку под описанием плагина, сразу
после автора, а имя автора стало ссылкой на его сайт.

= 0.1.2 =
Проверить обновление плагина теперь можно кнопкой, не дожидаясь, пока он
спросит сам. Блок услуг автора переехал в правую колонку вкладки «Состояние».

= 0.1.1 =
Исправлены три ошибки сборки: ложный вопрос про чужие файлы в папке приложения,
падение на значке сайта в формате `.ico` и столкновение двух сборок, запущенных
одновременно. Обновиться стоит всем, у кого включена ежедневная пересборка.

= 0.1.0 =
Первый выпуск.
