← Все кейсы

CASE STUDY / 13

WORDPRESS × RESEARCH

Сбор научных публикаций и организация PDF для исследовательской команды

Задача

Исследователи собирали публикации по нескольким темам и наборам поисковых запросов. Для каждой найденной работы приходилось отдельно проверять наличие PDF, скачивать файл и помещать его в нужную папку общей базы материалов. Часть публикаций доступна только как описание; у части PDF-ссылка есть, но возвращает страницу или ошибку. Ручной проход быстро превращается в повторяющуюся работу, в которой легко потерять источник, перепутать тему или повторно загрузить документ.

Нужен был один рабочий экран: запустить поиск по подготовленным запросам, увидеть найденные статьи и состояние их PDF, а затем отправить выбранные материалы в общую структуру. Если автоматический поиск файла не помог, исследователь должен иметь возможность добавить PDF вручную к той же записи.

Роль и объём

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

Отдельно спроектировал эксплуатационный контур: разграничение доступа, состояния фонового запуска, защита от запоздавших задач, безопасную загрузку внешних файлов и диагностику без записи API-ключей.

Ограничения

  • Поиск по нескольким наборам запросов и источникам может занять больше времени одного запроса из браузера. Обход нужно вынести в очередь и показывать его ход на странице.
  • Наличие ссылки с расширением .pdf не гарантирует, что сервер отдаст PDF. Перед учётом успешной загрузки требуется проверить ответ и содержимое файла.
  • Одна статья может встретиться по разным ключевым словам и в разных источниках. Перед отправкой файла в общую коллекцию нужно показать возможный дубль.
  • Внешние поисковые API и хранилище могут отказать независимо друг от друга. Ошибка одного этапа не должна превращаться в ложную отметку «файл отправлен».

Архитектура

Исследователь → экран WordPress
     ├── Настройки: группы и ключевые слова
     ├── Запуск поиска и прогресс по группам
     └── Результаты: PDF найден / недоступен / отправлен
                    │
                    ▼
              Action Scheduler
     ├── Идентификатор запуска и контроль актуальности задачи
     ├── Состояния pending / completed / failed
     ├── Тайм-аут зависшего запуска и безопасный новый старт
     └── Обход групп запросов по очереди
                    │
                    ▼
           Сервисы поиска публикаций
     ├── Адаптер каталога публикаций
     └── Адаптер поисковой выдачи статей
          ├── Метаданные публикаций
          ├── Поиск PDF-ссылок
          └── Безопасная загрузка и проверка PDF
                    │
                    ▼
       Отдельная таблица результатов MySQL
          ├── Тема, группа, запрос, источник, заголовок
          └── Ссылка и состояние PDF, состояние отправки
                    │
                    ▼
   Выбранные строки / ручной PDF → внешняя база материалов
          ├── Поиск или создание коллекции и группы
          ├── Проверка одноимённого файла в группе
          └── Отправка файла и обновление статуса строки

Поиск и размещение материалов разделены. Очередь собирает кандидатов и фиксирует результат в таблице; решение, какие PDF включить в общую базу, остаётся за исследователем.

Реализация

Наборы ключевых слов задаются в настройках. При запуске выбранная тема подставляется в шаблоны запросов, создаётся UUID прохода и первая задача Action Scheduler. После обработки группы задача ставит в очередь следующую. Перед изменением прогресса каждый обработчик повторно сверяет идентификатор и состояние запуска. Запоздавшая задача от предыдущего прохода поэтому не может отметить группу в новом исследовании.

Запуск имеет явные состояния pending, completed и failed, время последней активности и стабильный код ошибки. Неудача внешнего поискового API, некорректный JSON, ошибка постановки следующей задачи или исключение обработчика переводят проход в failed. Уже найденные материалы сохраняются и показываются исследователю. Если активность надолго прекратилась, проверка состояния закрывает зависший проход по тайм-ауту и разрешает новый запуск.

На странице прогресс рассчитывается по числу пройденных групп; найденные записи выбираются из таблицы по идентификатору запуска. Хранение результатов отдельно от обычных записей WordPress позволяет сохранить источник, поисковую фразу, исходный ответ API и два независимых статуса: PDF и отправки.

Один адаптер получает статьи из каталога научных публикаций, ищет связанные полнотекстовые материалы и извлекает PDF-ссылку. Второй разбирает поисковую выдачу, в которой PDF может быть указан как отдельный ресурс. Оба передают ссылку общему менеджеру файлов. Для внешнего адреса используется безопасный HTTP-клиент WordPress; перед сохранением проверяются код ответа, MIME-тип, сигнатура %PDF и предел в 50 МБ. Если файл не удалось получить, запись о публикации всё равно остаётся в результатах с соответствующим состоянием.

При отправке выбранной строки плагин находит или создаёт коллекцию по теме исследования и вложенную группу по набору запросов. Перед загрузкой ищет файл с таким же именем именно в этой группе. Если совпадение найдено, интерфейс просит исследователя подтвердить повторную отправку. Массовое действие обрабатывает выбранные строки последовательно; недоступный автоматически PDF можно загрузить вручную. Для ручного файла проверяются ошибка приёма, размер, расширение и MIME-тип. Статус отправки в таблице меняется после успешного ответа внешнего сервиса.

Сбои и диагностика

На рабочем экране видны состояние запуска, прогресс по группам, наличие PDF у каждой записи и факт отправки во внешнее хранилище. При сбое очередь получает состояние failed, интерфейс прекращает опрос, показывает понятное сообщение и сохраняет доступ к уже собранным результатам. Исследователь может устранить причину и начать новый проход без ручного изменения опций WordPress.

Диагностика отправляется в серверный PHP-журнал с категорией подсистемы. Перед записью известные секреты заменяются маркером, параметры авторизации в строках очищаются, а URL внешнего запроса журналируется без query string. Ответ внешнего сервиса целиком в лог не копируется. Так можно отличить транспортную ошибку, некорректный JSON, неподходящий файл и сбой фоновой задачи, не создавая доступные через сайт файлы с ключами интеграций.

При неудачной отправке документа строка не помечается как отправленная. Исследователь может повторить действие или приложить PDF вручную. Успешной группа считается после завершения запросов к источникам; HTTP-ошибка и повреждённый JSON не превращаются в пустой успешный результат.

границы решения

Запуск поиска, опрос состояния, поиск темы и операции с файлами доступны только авторизованному администратору. AJAX-обработчики проверяют nonce и право manage_options. API-ключи находятся в серверной конфигурации и не передаются браузеру.

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

Отметка отправки сохраняется после успешного ответа внешнего сервиса. WordPress и внешняя база не участвуют в общей транзакции, поэтому при крайне редком разрыве соединения после принятия файла сверка дубля остаётся необходимой частью повторной попытки.

Результат

Исследователь запускает поиск из одного экрана, получает статьи из нескольких источников с указанием доступности PDF и переносит выбранные документы в понятную структуру общей базы. Долгая работа выполняется в контролируемой очереди, сбой получает явное состояние, частичный результат сохраняется, а зависший проход не блокирует систему навсегда. Неудачная автоматическая загрузка не удаляет найденную публикацию: для неё остаётся ручной путь.

Решение сокращает ручной маршрут от поисковой фразы до разобранной библиотеки и при этом сохраняет контроль исследователя над составом материалов.

Стек

PHP · WordPress · MySQL · Action Scheduler · AJAX · JavaScript · ACF · REST API · PDF

Есть похожая задача?

Расскажите о текущей системе и нужных изменениях — обсудим следующий шаг.

Следующий кейс: Безопасный переход из персональной ссылки в клиентские сервисы