
📺 Jak pobrać filmy z playlisty YouTube przez API: działający kod w 15 minut
Wstawili Państwo link do filmu z YouTube w edytorze, działa. Ale gdy na stronie potrzebna jest cała playlista, która sama pobiera nowe filmy, ręczne kopiowanie linku za każdym razem staje się rutyną.
Skrypt w PHP z YouTube Data API v3 rozwiązuje to zadanie w całości: pobiera wszystkie filmy z dowolnej publicznej playlisty, zwraca JSON, a Państwo wyświetlają je w dowolny sposób, jako siatkę kart, listę, galerię. Konfiguracja zajmuje 15 minut, potrzebny jest tylko klucz API i podstawowy PHP.
Poniżej działający kod pod WordPress z obsługą błędów, paginacją i cache'owaniem. Podejście jest uniwersalne: działa w każdym projekcie PHP, nie tylko pod WP.
💡 Szybki przegląd:
- Tworzymy klucz API w Google Cloud Console i przypisujemy go do YouTube Data API v3
- Wysyłamy zapytanie do playlistItems i otrzymujemy JSON ze wszystkimi filmami z playlisty
- Parsujemy odpowiedź, zbieramy miniatury i linki, wyświetlamy w siatce na stronie
- Dodajemy paginację dla playlist dłuższych niż 50 filmów i cache'owanie przez set_transient()
Krok 1: Tworzymy klucz YouTube Data API v3
Klucz API identyfikuje Państwa aplikację przed YouTube i uwzględnia limity. Tworzy się go bezpłatnie, dzienny limit to 10 000 jednostek. Jeden klucz wystarcza z zapasem dla większości stron.
Proszę wejść do Google Cloud Console na swoim koncie Google. Proszę utworzyć nowy projekt, przycisk wyboru projektu na górnym pasku, następnie New Project. Proszę nazwać go sensownie, na przykład my-youtube-feed.
Po utworzeniu projektu proszę przejść do APIs & Services → Library. W pasku wyszukiwania proszę wpisać YouTube Data API v3 i kliknąć Enable. Bez tego kroku klucz nie zostanie przypisany do odpowiedniego API, a zapytania zwrócą błąd 403.
Teraz sam klucz. W bocznym menu proszę otworzyć Credentials, kliknąć Create Credentials → API key. System wygeneruje klucz i pokaże go w oknie modalnym. Proszę od razu go skopiować: po zamknięciu okna klucz jest widoczny na liście, ale jego wartość jest częściowo ukryta.
Koniecznie proszę kliknąć Restrict key. W sekcji API restrictions proszę wybrać YouTube Data API v3, wtedy klucz nie zadziała dla innych API, nawet jeśli trafi do publicznego repozytorium. Dla lokalnego środowiska deweloperskiego HTTP-referrer można pozostawić pusty.
Klucz ma postać AIzaSyD-.... Proszę zapisać go w wp-config.php przez define('YOUTUBE_API_KEY', '...') i dodać wp-config.php do .gitignore. Proszę nie umieszczać klucza bezpośrednio w kodzie szablonu.
Krok 2: Pobieramy filmy z playlisty
Do zapytania potrzebne są dwie rzeczy: klucz API i ID playlisty. ID pozyskuje się z URL: proszę otworzyć playlistę na YouTube, skopiować pasek adresu. Parametr list= w URL to właśnie playlist ID: na przykład PLp0YhAQYkolGq1e6r1m5....
Podstawowe zapytanie PHP do endpointu 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 }
Co tu się dzieje. part=snippet, prosimy o podstawowe dane: tytuł, opis, miniaturę, pozycję na playliście. Dla pełnego zestawu można podać snippet,contentDetails,status. maxResults=50, maksimum na jedno zapytanie, API domyślnie zwraca 5 rekordów, dlatego lepiej podać ten parametr jawnie. playlistId kodujemy przez urlencode() na wypadek znaków specjalnych.
Dla środowiska produkcyjnego file_get_contents() proszę zastąpić przez wp_remote_get() (w WordPress) lub cURL z timeoutem. Bezpośrednie wywołanie nie powiedzie się, jeśli Google jest chwilowo niedostępny lub sieć zwalnia. Oto wariant z obsługą błędów 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);
Dwa poziomy sprawdzania: najpierw is_wp_error() wyłapuje awarie sieciowe, potem weryfikujemy kod HTTP. Jeśli coś poszło nie tak, zwracamy pustą tablicę, strona nie pada.
Krok 3: Wyświetlamy listę filmów na stronie
API zwraca tablicę items. Każdy element to jeden film z playlisty. Struktura odpowiedzi:
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 }
Film jest identyfikowany przez resourceId.videoId. Z niego tworzy się link https://www.youtube.com/watch?v=<videoId>. Miniatura znajduje się w thumbnails w trzech rozdzielczościach: dla siatki kart proszę brać medium, dla zwartej listy default.
Kod wyświetlania dla WordPress, shortcode lub szablon strony:
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 }
Trzy kwestie, które oszczędzają czas na debugowaniu:
loading="lazy". Przy 50 filmach na stronie bez leniwego ładowania spadnie wynik PageSpeed. Atrybut mówi przeglądarce: ładuj obrazek dopiero, gdy użytkownik do niego przewinie.esc_html()** iesc_url().** Obowiązkowa sanityzacja dla WordPress. Tytuły filmów czasem zawierają cudzysłowy i encje HTML, bez escapowania zepsują układ strony.target="_blank"** zrel="noopener".** Otwieramy YouTube w nowej karcie, ale nie przekazujemy jej dostępu dowindow.opener, ochrona przed tab-napping.
CSS dla siatki, minimalny, pod standardowy szablon:
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 }
Siatka automatycznie dostosowuje się do szerokości ekranu: auto-fill + minmax(280px, 1fr) dają od jednej do kilku kolumn bez media queries.
Krok 4: Paginacja, limity i typowe błędy
Paginacja. Jedno zapytanie zwraca maksymalnie 50 filmów. Jeśli na playliście jest ich więcej, w odpowiedzi pojawia się pole nextPageToken. Proszę przekazać je w następnym zapytaniu, API zwróci następną stronę. Pętla:
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);
Pętla przerywa się po 500 filmach, rozsądny pułap dla strony internetowej. Bez ograniczenia ryzykują Państwo wyczerpanie całego limitu w kilka ładowań.
Limity. Każde wywołanie playlistItems.list zużywa 1 jednostkę limitu, co potwierdza oficjalna tabela limitów Google. Dzienny limit to 10 000 jednostek. Czyli 10 000 zapytań na dobę, z zapasem dla zdecydowanej większości stron. Ale jeśli playlista aktualizuje się często, proszę włączyć cache'owanie:
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);
Sześć godzin, rozsądny balans między świeżością a oszczędzaniem limitu. Dla niekrytycznych playlist proszę ustawić 12-24 godziny. get_transient() i set_transient(), natywne funkcje WordPress, współpracują z cache'em obiektowym (Redis/Memcached), jeśli jest skonfigurowany, w przeciwnym razie zapisują do wp_options.
Typowe błędy i co z nimi robić:
- 403 Forbidden. API nie jest włączone dla projektu w Google Cloud Console. Proszę wrócić do kroku 1: przycisk Enable dla YouTube Data API v3 musi być kliknięty. Proszę też sprawdzić, czy nie nałożono ograniczeń IP w ustawieniach klucza.
- 400 Bad Request, „API key not valid". Klucz został właśnie utworzony i jeszcze się nie aktywował. Proszę odczekać 2-5 minut: ograniczenia API propagują się nie natychmiast.
- 404 Not Found. Nieprawidłowy playlist ID lub playlista jest prywatna. Klucz API zwraca tylko publiczne i niepubliczne (unlisted) playlisty. Prywatnych nie, do nich wymagana jest autoryzacja OAuth.
- Pusta tablica
itemsprzy prawidłowym ID. Najprawdopodobniej playlista jest pusta. Proszę otworzyć URL playlisty w przeglądarce i upewnić się, że są na niej filmy.
💻 Wideo: YouTube Data API v3 w działaniu
Krótkie wideo na temat, pokazuje w praktyce cały proces od tworzenia klucza do wyświetlenia listy filmów:
⁉️🤔 Często zadawane pytania
Czy API działa z prywatnymi playlistami?
Nie.
playlistItems.listz kluczem API zwraca tylko playlisty publiczne i niepubliczne (unlisted). Do prywatnych wymagana jest autoryzacja OAuth: użytkownik musi jawnie zezwolić Państwa aplikacji na dostęp do swojego konta. Dla publicznej strony-agregatora klucz API jest wystarczający.
Czy można pobrać filmy z cudzej playlisty?
Tak, jeśli playlista jest publiczna. Klucz API nie jest powiązany z właścicielem playlisty, identyfikuje Państwa aplikację, a nie użytkownika YouTube. Każda publiczna playlista jest dostępna po ID, niezależnie od tego, kto ją utworzył.
Jak pobrać więcej niż 50 filmów naraz?
Nie da się, to twardy limit
maxResultsdlaplaylistItems, ustalony w dokumentacji Google. Proszę użyć paginacji przeznextPageToken(krok 4). Dla playlisty z 300 filmami potrzeba będzie 6 kolejnych zapytań, razem zużyją one 6 jednostek limitu z 10 000 dziennych.
Dlaczego nie wyświetlają się miniatury filmów?
Proszę sprawdzić URL w
thumbnails: pole nazywa sięurl, nielinkanisrc. Drugi powód, blokady reklam czasem odcinają domenęi.ytimg.com. Trzeci: niektóre stare filmy (sprzed 2010 roku) nie mają miniatur w wysokiej rozdzielczości, proszę braćdefault, on jest zawsze.
Co zrobić, jeśli klucz został skompromitowany?
Proszę natychmiast wejść do Google Cloud Console → Credentials, znaleźć klucz i kliknąć Delete. Proszę utworzyć nowy. Stary klucz zostanie dezaktywowany w ciągu 5 minut. Proszę przechowywać klucz przez
define('YOUTUBE_API_KEY', '...')wwp-config.phpi wykluczyć ten plik z repozytorium przez.gitignore.
Czy warto zawracać sobie głowę API, skoro można wstawić link do playlisty?
Jeśli na stronie wystarczy jedna statyczna playlista przez iframe, API nie jest potrzebne, YouTube daje gotowy kod do osadzenia. Ale gdy tylko pojawia się zadanie automatycznego pobierania nowych filmów, filtrowania po dacie, dostosowania układu strony lub wyświetlania miniatur w niestandardowym designie, API staje się jedyną działającą opcją.
Dla strony na WordPress połączenie wp_remote_get() + set_transient() całkowicie rozwiązuje kwestię limitów i szybkości: raz na kilka godzin skrypt pobiera JSON, cache'uje, a frontend pracuje z cache'em natychmiastowo. Playlista aktualizuje się sama, redaktor nie musi niczego klikać.
Jeśli szablon obsługuje dowolny PHP w szablonach, proszę wziąć kod z kroku 3, zmienić CSS pod swój design. Jeśli używany jest kreator stron, proszę opakować logikę PHP w shortcode i wstawiać gdziekolwiek przez [youtube_playlist id="PLp0..."].
Proszę spróbować z jedną playlistą: 15 minut na klucz i pierwsze zapytanie, a zobaczą Państwo, czy to podejście sprawdza się w Państwa zadaniu. A jeśli już używali Państwo API do innych celów, proszę napisać w komentarzach, który endpoint okazał się najbardziej przydatny.



