
📺 Как получить видео из плейлиста YouTube через API: рабочий код за 15 минут
Вставили ссылку на YouTube-видео в редактор, работает. Но когда на сайте нужен целый плейлист, который сам подхватывает новые видео, копировать ссылки вручную каждый раз превращается в рутину.
Скрипт на PHP с YouTube Data API v3 решает задачу полностью: забирает все видео из любого публичного плейлиста, отдаёт JSON, а вы выводите их как угодно, сеткой карточек, списком, галереей. Настройка занимает 15 минут, нужен только API-ключ и базовый PHP.
Ниже, рабочий код под WordPress с обработкой ошибок, пагинацией и кешированием. Подход универсальный: работает в любом PHP-проекте, не только под WP.
💡 Быстрый обзор:
- Создаём API-ключ в Google Cloud Console и привязываем к YouTube Data API v3
- Отправляем запрос к playlistItems и получаем JSON со всеми видео плейлиста
- Парсим ответ, собираем превью и ссылки, выводим сеткой на странице
- Добавляем пагинацию для плейлистов длиннее 50 видео и кеширование через set_transient()
Шаг 1: Создаём ключ YouTube Data API v3
API-ключ идентифицирует ваше приложение перед YouTube и учитывает квоты. Создаётся бесплатно, суточный лимит, 10 000 единиц. Одного ключа хватает с запасом для большинства сайтов.
Зайдите в Google Cloud Console под своим Google-аккаунтом. Создайте новый проект, кнопка выбора проекта в верхней панели, затем New Project. Назовите осмысленно, например my-youtube-feed.
После создания проекта перейдите в APIs & Services → Library. В строке поиска наберите YouTube Data API v3 и нажмите Enable. Без этого шага ключ не привяжется к нужному API, и запросы вернут 403.
Теперь, сам ключ. В боковом меню откройте Credentials, нажмите Create Credentials → API key. Система сгенерирует ключ и покажет его в модальном окне. Сразу скопируйте: после закрытия окна ключ виден в списке, но его значение частично скрыто.
Обязательно нажмите Restrict key. В разделе API restrictions выберите YouTube Data API v3, тогда ключ не сработает для других API, даже если попадёт в открытый репозиторий. Для локальной разработки HTTP-referrer можно оставить пустым.
Ключ выглядит как AIzaSyD-.... Сохраните его в wp-config.php через define('YOUTUBE_API_KEY', '...') и добавьте wp-config.php в .gitignore. Не хардкодьте ключ в коде темы.
Шаг 2: Получаем видео из плейлиста
Для запроса нужны две вещи: API-ключ и ID плейлиста. ID извлекается из URL: откройте плейлист на YouTube, скопируйте адресную строку. Параметр list= в URL и есть playlist ID: например, PLp0YhAQYkolGq1e6r1m5....
Базовый PHP-запрос к endpoint playlistItems:
1 $api_key = 'AIzaSy...'; // ваш ключ из шага 1 2 $playlist_id = 'PLp0YhAQYkolG...'; // ID плейлиста из URL 3 4 $api_url = 'https://www.googleapis.com/youtube/v3/playlistItems' . 5 '?part=snippet' . 6 '&maxResults=50' . 7 '&playlistId=' . urlencode($playlist_id) . 8 '&key=' . $api_key; 9 10 $response = file_get_contents($api_url); 11 $data = json_decode($response, true); 12 13 if (json_last_error() !== JSON_ERROR_NONE) { 14 die('Ошибка парсинга JSON: ' . json_last_error_msg()); 15 }
Что здесь происходит. part=snippet, запрашиваем базовые данные: заголовок, описание, превью, позицию в плейлисте. Для полного набора можно указать snippet,contentDetails,status. maxResults=50, максимум за один запрос, API по умолчанию отдаёт 5 записей, поэтому параметр лучше указывать явно. playlistId кодируем через urlencode() на случай спецсимволов.
Для продакшена file_get_contents() замените на wp_remote_get() (в WordPress) или cURL с таймаутом. Прямой вызов упадёт, если Google временно недоступен или сеть тормозит. Вот вариант с обработкой HTTP-ошибок:
1 $response = wp_remote_get($api_url, [ 2 'timeout' => 15, 3 'headers' => ['Accept' => 'application/json'], 4 ]); 5 6 if (is_wp_error($response)) { 7 error_log('YouTube API error: ' . $response->get_error_message()); 8 return []; 9 } 10 11 $http_code = wp_remote_retrieve_response_code($response); 12 if ($http_code !== 200) { 13 error_log('YouTube API HTTP ' . $http_code); 14 return []; 15 } 16 17 $body = wp_remote_retrieve_body($response); 18 $data = json_decode($body, true);
Два уровня проверки: сначала is_wp_error() ловит сетевые сбои, затем сверяем HTTP-код. Если что-то пошло не так, возвращаем пустой массив, сайт не падает.
Шаг 3: Выводим список видео на странице
API возвращает массив items. Каждый элемент, одно видео плейлиста. Структура ответа:
1 { 2 "items": [ 3 { 4 "snippet": { 5 "title": "Название видео", 6 "description": "Описание...", 7 "thumbnails": { 8 "default": { "url": "https://i.ytimg.com/.../default.jpg" }, 9 "medium": { "url": "https://i.ytimg.com/.../mqdefault.jpg" }, 10 "high": { "url": "https://i.ytimg.com/.../hqdefault.jpg" } 11 }, 12 "resourceId": { 13 "videoId": "dQw4w9WgXcQ" 14 } 15 } 16 } 17 ] 18 }
Видео идентифицируется по resourceId.videoId. Из него собирается ссылка https://www.youtube.com/watch?v=<videoId>. Превью лежит в thumbnails в трёх разрешениях: для сетки карточек берите medium, для компактного списка, default.
Код вывода для WordPress, шорткод или шаблон страницы:
1 if (! empty($data['items'])) { 2 echo '<div class="yt-playlist-grid">'; 3 4 foreach ($data['items'] as $item) { 5 $title = esc_html($item['snippet']['title']); 6 $video_id = esc_attr($item['snippet']['resourceId']['videoId']); 7 $thumbnail = esc_url($item['snippet']['thumbnails']['medium']['url']); 8 $link = 'https://www.youtube.com/watch?v=' . $video_id; 9 10 printf( 11 '<a href="%s" class="yt-card" target="_blank" rel="noopener">' 12 . '<img src="%s" alt="%s" loading="lazy">' 13 . '<span>%s</span></a>', 14 $link, $thumbnail, $title, $title 15 ); 16 } 17 18 echo '</div>'; 19 }
Три момента, которые экономят время на отладке:
loading="lazy". При 50 видео на странице без ленивой загрузки просядет PageSpeed. Атрибут говорит браузеру: загружай картинку только когда до неё докрутили.esc_html()** иesc_url().** Обязательная санитация для WordPress. Названия видео иногда содержат кавычки и HTML-сущности, без экранирования сломают вёрстку.target="_blank"** сrel="noopener".** Открываем YouTube в новой вкладке, но не отдаём ей доступ кwindow.opener, защита от tab-napping.
CSS для сетки, минимальный, под стандартную тему:
1 .yt-playlist-grid { 2 display: grid; 3 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); 4 gap: 20px; 5 } 6 .yt-card { 7 text-decoration: none; 8 color: inherit; 9 border-radius: 8px; 10 overflow: hidden; 11 transition: transform 0.2s; 12 } 13 .yt-card:hover { 14 transform: translateY(-2px); 15 } 16 .yt-card img { 17 width: 100%; 18 aspect-ratio: 16 / 9; 19 object-fit: cover; 20 } 21 .yt-card span { 22 display: block; 23 padding: 10px; 24 font-weight: 600; 25 font-size: 14px; 26 }
Сетка автоматически подстраивается под ширину экрана: auto-fill + minmax(280px, 1fr) дают от одной до нескольких колонок без медиазапросов.
Шаг 4: Пагинация, квоты и типичные ошибки
Пагинация. Один запрос отдаёт максимум 50 видео. Если в плейлисте больше, в ответе появляется поле nextPageToken. Передайте его в следующем запросе, API вернёт следующую страницу. Цикл:
1 $all_items = []; 2 $page_token = null; 3 4 do { 5 $url = $api_url . '&pageToken=' . urlencode($page_token ?? ''); 6 // ... запрос к API ... 7 $all_items = array_merge($all_items, $data['items'] ?? []); 8 $page_token = $data['nextPageToken'] ?? null; 9 } while ($page_token && count($all_items) < 500);
Цикл прерывается на 500 видео, разумный потолок для страницы сайта. Без ограничения рискуете выбрать всю квоту за пару загрузок.
Квоты. Каждый вызов playlistItems.list расходует 1 единицу квоты, это подтверждено официальной таблицей квот Google. Суточный лимит, 10 000 единиц. То есть 10 000 запросов в сутки, с запасом для подавляющего большинства сайтов. Но если плейлист обновляется часто, ставьте кеширование:
1 $cache_key = 'yt_playlist_' . md5($playlist_id); 2 $cached_data = get_transient($cache_key); 3 4 if ($cached_data !== false) { 5 return $cached_data; 6 } 7 8 // ... запрос к API ... 9 10 set_transient($cache_key, $data, HOUR_IN_SECONDS * 6);
Шесть часов, разумный баланс между свежестью и экономией квоты. Для некритичных плейлистов ставьте 12-24 часа. get_transient() и set_transient(), нативные функции WordPress, работают с объектным кешем (Redis/Memcached), если он настроен, иначе пишут в wp_options.
Типичные ошибки и что с ними делать:
- 403 Forbidden. API не включён для проекта в Google Cloud Console. Вернитесь к шагу 1: кнопка Enable для YouTube Data API v3 должна быть нажата. Проверьте также, не наложено ли ограничение по IP в настройках ключа.
- 400 Bad Request, «API key not valid». Ключ только что создан и ещё не активировался. Подождите 2-5 минут: ограничения API распространяются не мгновенно.
- 404 Not Found. Неверный playlist ID, или плейлист приватный. API-ключ возвращает только публичные и скрытые по ссылке (unlisted) плейлисты. Приватные, нет, для них нужна OAuth-авторизация.
- Пустой массив
itemsпри валидном ID. Скорее всего, плейлист пуст. Откройте URL плейлиста в браузере и убедитесь, что видео есть.
💻 Видео: YouTube Data API v3 в действии
Короткое видео по теме, наглядно показывает весь процесс от создания ключа до вывода списка видео:
⁉️🤔 Частые вопросы
Работает ли API с приватными плейлистами?
Нет.
playlistItems.listс API-ключом возвращает только публичные и скрытые по ссылке (unlisted) плейлисты. Для приватных нужна OAuth-авторизация: пользователь должен явно разрешить вашему приложению доступ к своему аккаунту. Для публичного сайта-агрегатора API-ключа достаточно.
Можно ли получить видео из чужого плейлиста?
Да, если плейлист публичный. API-ключ не привязан к владельцу плейлиста, он идентифицирует ваше приложение, а не пользователя YouTube. Любой публичный плейлист доступен по ID, независимо от того, кто его создал.
Как получить больше 50 видео за раз?
Никак, это аппаратный лимит
maxResultsдляplaylistItems, зафиксированный в документации Google. Используйте пагинацию черезnextPageToken(шаг 4). Для плейлиста из 300 видео понадобится 6 последовательных запросов, вместе они потратят 6 единиц квоты из 10 000 суточных.
Почему не показываются превью видео?
Проверьте URL в
thumbnails: поле называетсяurl, неlinkи неsrc. Вторая причина, блокировщики рекламы иногда режут доменi.ytimg.com. Третья: некоторые старые видео (до 2010 года) не имеют превью высокого разрешения, беритеdefault, он есть всегда.
Что делать, если ключ скомпрометирован?
Немедленно зайдите в Google Cloud Console → Credentials, найдите ключ и нажмите Delete. Создайте новый. Старый ключ деактивируется в течение 5 минут. Храните ключ через
define('YOUTUBE_API_KEY', '...')вwp-config.phpи исключите этот файл из репозитория через.gitignore.
Стоит ли заморачиваться с API, если можно вставить ссылку на плейлист?
Если на сайте достаточно одного статичного плейлиста через iframe, API не нужен, YouTube даёт готовый код встраивания. Но как только появляется задача автоматически подхватывать новые видео, фильтровать по дате, кастомизировать вёрстку или выводить превью в нестандартном дизайне, API становится единственным рабочим вариантом.
Для WordPress-сайта связка wp_remote_get() + set_transient() полностью снимает вопрос квот и скорости: раз в несколько часов скрипт забирает JSON, кеширует, а фронт работает с кешом мгновенно. Плейлист обновляется сам, редактору ничего нажимать не нужно.
Если тема поддерживает произвольный PHP в шаблонах, берите код из шага 3, меняйте CSS под свой дизайн. Если используется конструктор, оберните PHP-логику в шорткод и вставляйте куда угодно через [youtube_playlist id="PLp0..."].
Попробуйте с одного плейлиста: 15 минут на ключ и первый запрос, и вы увидите, работает ли подход под вашу задачу. А если уже использовали API для других целей, напишите в комментариях, какой endpoint оказался самым полезным.



