PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.4.8
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.4.8
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Providers / Youtube.php
embedpress / EmbedPress / Providers Last commit date
TemplateLayouts 8 months ago AirTable.php 1 year ago Boomplay.php 1 year ago Calendly.php 2 years ago Canva.php 1 year ago FITE.php 1 year ago GettyImages.php 9 months ago Giphy.php 2 years ago GitHub.php 3 years ago GoogleCalendar.php 8 months ago GoogleDocs.php 2 years ago GoogleDrive.php 2 years ago GoogleMaps.php 2 years ago GooglePhotos.php 7 months ago Gumroad.php 2 years ago InstagramFeed.php 6 months ago LinkedIn.php 2 years ago Meetup.php 6 months ago NRKRadio.php 2 years ago OneDrive.php 11 months ago OpenSea.php 9 months ago SelfHosted.php 2 years ago Spreaker.php 1 year ago TikTok.php 2 years ago Twitch.php 2 years ago Wistia.php 6 months ago Wrapper.php 3 years ago X.php 2 years ago Youtube.php 9 months ago index.html 7 years ago
Youtube.php
928 lines
1 <?php
2
3 /**
4 * Youtube.php
5 *
6 * @package Embera
7 * @author Michael Pratt <yo@michael-pratt.com>
8 * @link http://www.michael-pratt.com/
9 *
10 * For the full copyright and license information, please view the LICENSE
11 * file that was distributed with this source code.
12 */
13
14 namespace EmbedPress\Providers;
15
16 use Embera\Provider\ProviderAdapter;
17 use Embera\Provider\ProviderInterface;
18 use Embera\Url;
19
20 use EmbedPress\Includes\Classes\Helper;
21
22 use EmbedPress\Providers\TemplateLayouts\YoutubeLayout;
23
24 /**
25 * youtube.com Provider
26 * @link https://youtube.com
27 * @link https://youtube-eng.googleblog.com/2009/10/oembed-support_9.html
28 */
29
30
31 class Youtube extends ProviderAdapter implements ProviderInterface {
32 /** inline {@inheritdoc} */
33 protected $shouldSendRequest = false;
34 public static $curltimeout = 30;
35 /** inline {@inheritdoc} */
36 protected $endpoint = 'https://www.youtube.com/oembed?format=json&scheme=https';
37 protected static $channel_endpoint = 'https://www.googleapis.com/youtube/v3/';
38 /** @var array Array with allowed params for the current Provider */
39 protected $allowedParams = [ 'maxwidth', 'maxheight', 'pagesize', 'thumbnail', 'gallery', 'hideprivate', 'columns', 'ispagination', 'gapbetweenvideos', 'ytChannelLayout' ];
40
41 /** inline {@inheritdoc} */
42 protected static $hosts = [
43 'm.youtube.com', 'youtube.com', 'youtu.be',
44 ];
45
46 /** inline {@inheritdoc} */
47 protected $httpsSupport = true;
48
49 public function getAllowedParams(){
50 return $this->allowedParams;
51 }
52
53 /** inline {@inheritdoc} */
54 public function validateUrl(Url $url) {
55 return (bool) (preg_match('~\/channel\/|\/c\/|\/user\/|\/@\w+|(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(\w+)[^?\/]*$~i', (string) $url));
56 }
57
58 public function validateTYLiveUrl($url) {
59 return (bool) (preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/(?:channel|c|user)\/\w+\/live|@\w+\/live)~i', (string) $url));
60 }
61
62 /** inline {@inheritdoc} */
63 public function normalizeUrl(Url $url) {
64 return $url;
65 }
66
67
68 public function isChannel($url = null) {
69 if (empty($url)) {
70 $url = $this->url;
71 }
72 $channel = $this->getChannel($url);
73 return !empty($channel['id']);
74 }
75
76 public function getChannel($url = null) {
77 $channelId = 'unknown_id'; // temporarily assigned a placeholder value for demonstration purposes
78
79 if (empty($url)) {
80 $url = $this->url;
81 }
82 preg_match('~\/(channel|c|user)\/(.+)~i', (string) $url, $matches);
83 if(empty($matches[1])){
84 preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(\w+)[^?\/]*$~i', (string) $url, $matches);
85 if(!empty($matches[1])){
86 return [
87 "type" => 'user',
88 "id" => $matches[1],
89 ];
90 }
91 }
92
93
94
95 if(empty($matches[1])){
96 preg_match('~\/(@)(\w+)~i', (string) $url, $matches);
97 if(!empty($matches[1])){
98 if(!empty($this->get_youtube_handler($this->url))){
99 if(!empty($this->get_channel_id_by_handler($this->get_youtube_handler($this->url)))){
100 $channelId = $this->get_channel_id_by_handler($this->get_youtube_handler($this->url));
101 }
102 }
103 return [
104 "type" => 'user',
105 "id" => $channelId,
106 ];
107 }
108 }
109 return [
110 "type" => isset($matches[1]) ? $matches[1] : '',
111 "id" => isset($matches[2]) ? $matches[2] : '',
112 ];
113 }
114
115 /** inline {@inheritdoc} */
116 public function getEndpoint() {
117 if ($this->isChannel()) {
118 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/channels';
119 return $apiEndpoint;
120 }
121 return (string) $this->endpoint;
122 }
123
124 protected function get_api_key() {
125 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
126 return !empty($settings['api_key']) ? $settings['api_key'] : '';
127 }
128
129 protected function get_pagesize() {
130 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
131 return !empty($settings['pagesize']) ? $settings['pagesize'] : '';
132 }
133
134 /** inline {@inheritdoc} */
135 public function getParams() {
136 $params = parent::getParams();
137
138 if ($this->isChannel() && $this->get_api_key()) {
139 $channel = $this->getChannel();
140 $params['part'] = 'contentDetails,snippet';
141 $params['key'] = $this->get_api_key();
142 if ($channel['type'] == 'c') {
143 $params['forUsername'] = $channel['id'];
144 } else {
145 $params['id'] = $channel['id'];
146 }
147 unset($params['url']);
148 }
149 return $params;
150 }
151
152 /**
153 * Builds a valid Oembed query string based on the given parameters,
154 * Since this method uses the http_build_query function, there is no
155 * need to pass urlencoded parameters, http_build_query already does
156 * this for us.
157 *
158 * @param string $endpoint The Url to the Oembed endpoint
159 * @param array $params Parameters for the query string
160 * @return string
161 */
162
163 protected function constructUrl($endpoint, array $params = array())
164 {
165 $endpoint = self::$channel_endpoint . $endpoint;
166
167 return $endpoint . ((strpos($endpoint, '?') === false) ? '?' : '&') . http_build_query(array_filter($params));
168 }
169
170 public function getStaticResponse() {
171 $results = [
172 "title" => "",
173 "type" => "video",
174 'provider_name' => $this->getProviderName(),
175 "provider_url" => "https://www.youtube.com/",
176 'html' => '',
177 ];
178
179 $params = $this->getParams();
180
181 if (preg_match("/^https?:\/\/(?:www\.)?youtube\.com\/channel\/([\w-]+)\/live$/", $this->url, $matches) || $this->validateTYLiveUrl($this->url)) {
182
183 if(!empty($matches[1])){
184 $channelId = $matches[1];
185 }
186
187 if(!empty($this->get_youtube_handler($this->url))){
188 if(!empty($this->get_channel_id_by_handler($this->get_youtube_handler($this->url)))){
189 $channelId = $this->get_channel_id_by_handler($this->get_youtube_handler($this->url));
190 }
191 }
192
193
194
195 $embedUrl = 'https://www.youtube.com/embed/live_stream?channel='.$channelId.'&feature=oembed';
196
197 $attr = [];
198 $attr[] = 'width="'.esc_attr($params['maxheight']).'"';
199 $attr[] = 'height="'.esc_attr($params['maxheight']).'";';
200 $attr[] = 'src="' . esc_url($embedUrl) . '"';
201 $attr[] = 'frameborder="0"';
202 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
203 $attr[] = 'allowfullscreen';
204
205 $results['html'] = '<iframe ' . implode(' ', $attr) . '></iframe>';
206 }
207 else if($this->isChannel()){
208 $channel = $this->getChannelGallery();
209 $results = array_merge($results, $channel);
210 }
211
212 return $results;
213 }
214
215 public function getChannelPlaylist(){
216 $result = [
217 "playlistID" => '',
218 "title" => '',
219 ];
220 $channel = $this->getChannel();
221 $channel_url = $this->constructUrl('channels', $this->getParams());
222 $transient_key = 'ep_embed_youtube_channel_playlist_id_' . md5($channel_url);
223 $jsonResult = get_transient($transient_key);
224
225 if(!empty($jsonResult)){
226 return $jsonResult;
227 }
228
229 if($channel['type'] == 'user' || $channel['type'] == 'c'){
230 $this->getChannelIDbyUsername();
231 $channel_url = $this->constructUrl('channels', $this->getParams());
232 }
233
234 if (empty($this->get_api_key())) {
235 $result['error'] = true;
236 $result['html'] = $this->get_api_key_error_message();
237 return $result;
238 }
239
240 $apiResult = wp_remote_get($channel_url, array('timeout' => self::$curltimeout));
241 if (is_wp_error($apiResult)) {
242 $result['error'] = true;
243 $result['html'] = $this->clean_api_error_html($apiResult->get_error_message(), true);
244 set_transient($transient_key, $result, 10);
245 return $result;
246 }
247 $jsonResult = json_decode($apiResult['body']);
248
249
250 if (isset($jsonResult->error)) {
251 $result['error'] = true;
252 if (isset($jsonResult->error->message)) {
253 $result['html'] = $this->clean_api_error_html($jsonResult->error->message, true);
254 }
255 else{
256 $result['html'] = $this->clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
257 }
258 set_transient($transient_key, $result, MINUTE_IN_SECONDS);
259 return $result;
260 }
261 elseif(!empty($jsonResult->items[0]->contentDetails->relatedPlaylists->uploads)){
262 $result['playlistID'] = $jsonResult->items[0]->contentDetails->relatedPlaylists->uploads;
263 $result['title'] = isset($jsonResult->items[0]->snippet->title) ? $jsonResult->items[0]->snippet->title : '';
264 set_transient($transient_key, $result, DAY_IN_SECONDS);
265 }
266
267 return $result;
268 }
269
270 public function get_youtube_handler($url){
271 // preg_match('/^https:\/\/www.youtube.com\/@(.+)\/live$/i', $url, $matches);
272 preg_match('/^https:\/\/www.youtube.com\/@([^\/?]+)/i', $url, $matches);
273
274
275 $handle_name = '';
276 if(!empty($matches[1])){
277 $handle_name = $matches[1];
278 }
279
280 return $handle_name;
281 }
282
283 public function getChannelIDbyUsername(){
284 $url = $this->getUrl();
285 $apiResult = wp_remote_get($url, array('timeout' => self::$curltimeout));
286
287 if (!is_wp_error($apiResult)) {
288 $channel_html = $apiResult['body'];
289 preg_match("/<meta\s+itemprop=[\"']channelId[\"']\s+content=[\"'](.*?)[\"']\/?>/", $channel_html, $matches);
290 if(!empty($matches[1])){
291 $url = "https://www.youtube.com/channel/{$matches[1]}";
292 $url = $this->normalizeUrl(new Url($url));
293 }
294 }
295 }
296
297
298 public function get_channel_id_by_handler($handle)
299 {
300 $transient_key = 'channel_id_' . md5($handle);
301 $channel_id = get_transient($transient_key);
302
303 if (false === $channel_id) {
304 $ch = curl_init();
305
306 $channel_handle = "https://www.youtube.com/@{$handle}";
307
308 curl_setopt($ch, CURLOPT_URL, $channel_handle);
309 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
310
311 $response = curl_exec($ch);
312
313 if (curl_errno($ch)) {
314 return 'cURL error: ' . curl_error($ch);
315 }
316
317 curl_close($ch);
318
319 $pattern = '/(<link rel="canonical" href="https:\/\/www\.youtube\.com\/channel\/)(.{1,50})(">)/';
320 if (preg_match($pattern, $response, $matches)) {
321 $channel_id = $matches[2];
322 set_transient($transient_key, $channel_id, 30 * DAY_IN_SECONDS);
323
324 return $channel_id;
325 } else {
326 return "Not a channel URL";
327 }
328 } else {
329 return $channel_id;
330 }
331 }
332
333 public function layout_data(){
334 $data = [];
335 $data['get_pagesize'] = $this->get_pagesize();
336 $data['get_api_key'] = $this->get_api_key();
337 $data['get_api_key_error_message'] = $this->get_api_key_error_message();
338 $data['get_channel_info'] = $this->get_channel_info();
339 $data['get_api_key'] = $this->get_api_key();
340 $data['curltimeout'] = self::$curltimeout;
341 $data['self::class'] = self::class;
342
343 return $data;
344
345 }
346
347
348 /** inline {@inheritdoc} */
349 public function getChannelGallery() {
350 $response = [];
351 $channel = $this->getChannelPlaylist();
352 if(!empty($channel['error'])){
353 return $channel;
354 }
355 if (!empty($channel["playlistID"])) {
356 $params = $this->getParams();
357 $the_playlist_id = $channel["playlistID"];
358 $rel = 'https://www.youtube.com/embed?listType=playlist&list=' . esc_attr($the_playlist_id);
359 $title = $channel['title'];
360 $main_iframe = "";
361 $gallery_args = [
362 'playlistId' => $the_playlist_id,
363 ];
364 if(!empty($params['pagesize'])){
365 $gallery_args['pagesize'] = $params['pagesize'];
366 }
367
368 $layout_data = $this->layout_data();
369
370
371 // $gallery = $this->get_gallery_page($gallery_args);
372
373 $channel_layout = 'layout-gallery';
374
375 $gallery = YoutubeLayout::create_youtube_layout($gallery_args, $layout_data, $channel_layout, $this->url);
376
377 if(isset($params['ytChannelLayout'])){
378 if($params['ytChannelLayout'] === 'gallery'){
379 $channel_layout = 'layout-gallery';
380
381 }
382 else if($params['ytChannelLayout'] === 'grid'){
383 $channel_layout = 'layout-grid';
384 }
385 else if($params['ytChannelLayout'] === 'list'){
386 $channel_layout = 'layout-list';
387
388 }
389 else if($params['ytChannelLayout'] === 'carousel'){
390 $channel_layout = 'layout-carousel';
391
392 }
393
394
395
396 $gallery = YoutubeLayout::create_youtube_layout($gallery_args, $layout_data, $params['ytChannelLayout'], $this->url);
397
398 }
399
400 $main_iframe = '';
401 if (!empty($gallery->first_vid) && empty($params['ytChannelLayout']) || $params['ytChannelLayout'] === 'gallery') {
402 $rel = "https://www.youtube.com/embed/{$gallery->first_vid}?feature=oembed";
403 $main_iframe = "<div class='ep-first-video'><iframe width='{$params['maxwidth']}' height='{$params['maxheight']}' src='$rel' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen title='{$title}'></iframe></div>";
404 }
405
406 if (!apply_filters('embedpress/is_allow_rander', false) && isset($params['ytChannelLayout']) && ($params['ytChannelLayout'] == 'grid' || $params['ytChannelLayout'] == 'carousel')) {
407 return [];
408 }
409
410 if ($gallery->html) {
411 $styles = $this->styles($params, $this->getUrl());
412 $html_content = $main_iframe . $gallery->html . ' ' . $styles;
413
414 if ($this->validateTYLiveUrl($this->getUrl())) {
415 return [
416 "title" => $title,
417 "html" => "<div class='ep-player-wrap'>$main_iframe $styles</div>",
418 ];
419 }
420
421 return [
422 "title" => $title,
423 "html" => "<div class='ep-player-wrap $channel_layout'>$html_content</div>",
424 ];
425 }
426
427 }
428 elseif ($this->isChannel() && empty($this->get_api_key()) && current_user_can('manage_options')) {
429 return [
430 "html" => "<div class='ep-player-wrap'>" . __('Please enter your YouTube API key to embed YouTube Channel.', 'embedpress') . "</div>",
431 ];
432 }
433
434 return $response;
435 }
436
437
438 public function get_channel_info() {
439 $api_key = $this->get_api_key();
440 $channel_id = $this->getChannel($this->url);
441 $channel_id = $channel_id['id'];
442
443
444 // Create a unique transient key based on the channel ID
445 $transient_key = 'youtube_channel_info_' . $channel_id;
446
447 // Attempt to get cached response
448 $channel_info = get_transient($transient_key);
449
450 if ($channel_info === false) {
451 // No cached response, make the API call
452 $endpoint = "https://www.googleapis.com/youtube/v3/channels?part=snippet%2Cstatistics&id=$channel_id&key=$api_key";
453 $response = wp_remote_get($endpoint);
454
455 if (is_wp_error($response)) {
456 return 'Error fetching channel info';
457 }
458
459 $body = wp_remote_retrieve_body($response);
460 $data = json_decode($body, true);
461
462 if (empty($data['items'])) {
463 return 'No channel information found';
464 }
465
466 $channel_info = $data['items'][0];
467
468
469 // Cache the response for 1 hour
470 set_transient($transient_key, $channel_info, HOUR_IN_SECONDS);
471 }
472
473 update_option('youtube_channel_info_'. md5($this->url), $channel_info);
474
475
476 return $channel_info;
477
478 }
479
480
481 public function get_layout() {
482 $params = $this->getParams();
483 return isset($params['ytChannelLayout']) ? $params['ytChannelLayout'] : '';
484 }
485
486 /**
487 * Undocumented function
488 *
489 * @param array $options
490 * @return object
491 */
492 public function get_gallery_page($options) {
493
494 $nextPageToken = '';
495 $prevPageToken = '';
496 $gallobj = new \stdClass();
497 $options = wp_parse_args($options, [
498 'playlistId' => '',
499 'pageToken' => '',
500 'pagesize' => $this->get_pagesize() ? $this->get_pagesize() : 6,
501 'currentpage' => '',
502 'columns' => 3,
503 'ytChannelLayout' => 'gallery',
504 'thumbnail' => 'medium',
505 'gallery' => true,
506 'autonext' => true,
507 'thumbplay' => true,
508 'apiKey' => $this->get_api_key(),
509 'hideprivate' => '',
510 ]);
511 $options['pagesize'] = $options['pagesize'] > 50 ? 50 : $options['pagesize'];
512 $options['pagesize'] = $options['pagesize'] < 1 ? 1 : $options['pagesize'];
513
514 if (empty($options['apiKey'])) {
515 $gallobj->html = $this->get_api_key_error_message();
516 return $gallobj;
517 }
518
519 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet,status,contentDetails&playlistId=' . $options['playlistId']
520 . '&maxResults=' . $options['pagesize']
521 . '&key=' . $options['apiKey'];
522 if ($options['pageToken'] != null) {
523 $apiEndpoint .= '&pageToken=' . $options['pageToken'];
524 }
525
526
527
528 $transient_key = 'ep_embed_youtube_channel_' . md5($apiEndpoint);
529 $gallobj->transient_key = $transient_key;
530 $jsonResult = get_transient($transient_key);
531
532
533 if (empty($jsonResult)) {
534 $apiResult = wp_remote_get($apiEndpoint, array('timeout' => self::$curltimeout));
535 if (is_wp_error($apiResult)) {
536 $gallobj->html = $this->clean_api_error_html($apiResult->get_error_message(), true);
537 return $gallobj;
538 }
539 $jsonResult = json_decode($apiResult['body']);
540
541 if (empty($jsonResult->error)) {
542 set_transient($transient_key, $jsonResult, MINUTE_IN_SECONDS * 20);
543 }
544 else{
545 set_transient($transient_key, $jsonResult, 10);
546 }
547 }
548
549
550
551 if (isset($jsonResult->error)) {
552 if(!empty($jsonResult->error->errors[0]->reason) && $jsonResult->error->errors[0]->reason == 'playlistNotFound'){
553 $gallobj->html = $this->clean_api_error_html(__('There is nothing on the playlist.', 'embedpress'));
554 return $gallobj;
555 }
556 if (isset($jsonResult->error->message)) {
557 $gallobj->html = $this->clean_api_error_html($jsonResult->error->message);
558 return $gallobj;
559 }
560 $gallobj->html = $this->clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
561 return $gallobj;
562 }
563
564
565
566 $resultsPerPage = $jsonResult->pageInfo->resultsPerPage;
567 $totalResults = $jsonResult->pageInfo->totalResults;
568 $totalPages = ceil($totalResults / $resultsPerPage);
569
570 if (isset($jsonResult->nextPageToken)) {
571 $nextPageToken = $jsonResult->nextPageToken;
572 }
573
574 if (isset($jsonResult->prevPageToken)) {
575 $prevPageToken = $jsonResult->prevPageToken;
576 }
577
578
579 if (!empty($jsonResult->items) && is_array($jsonResult->items)) :
580 if($options['gallery'] === "false"){
581 $gallobj->html = "";
582 if(count($jsonResult->items) === 1){
583 $gallobj->first_vid = $this->get_id($jsonResult->items[0]);
584 }
585 return $gallobj;
586 }
587
588 if(count($jsonResult->items) === 1 && empty($nextPageToken) && empty($prevPageToken)){
589 $gallobj->first_vid = $this->get_id($jsonResult->items[0]);
590 $gallobj->html = "";
591 return $gallobj;
592 }
593
594 if (strpos($options['playlistId'], 'UU') === 0) {
595 // sort only channels
596 usort($jsonResult->items, array(self::class, 'compare_vid_date')); // sorts in place
597 }
598
599 ob_start();
600
601 ?>
602
603 <div class="ep-youtube__content__block" data-unique-id="<?php echo wp_rand(); ?>">
604 <div class="youtube__content__body">
605 <?php
606 ?>
607
608 <div class="content__wrap">
609
610 <?php
611
612 $data = $this->layout_data();
613
614
615 $channel_info = get_option('youtube_channel_info_'.md5($options['channel_url']));
616
617 $channelTitle = isset($channel_info['snippet']['title']) ? $channel_info['snippet']['title'] : null;
618 $channelThumb = isset($channel_info['snippet']['thumbnails']['high']['url']) ? $channel_info['snippet']['thumbnails']['high']['url'] : null;
619 $layout = $this->get_layout();
620
621
622 if($layout === 'gallery'){
623 echo YoutubeLayout::create_gallery_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
624 }
625 else if($layout === 'grid'){
626 do_action('embedpress/youtube_grid_layout', $jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
627 }
628 else if($layout === 'list'){
629 echo YoutubeLayout::create_list_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
630 }
631 else if($layout === 'carousel'){
632 do_action('embedpress/youtube_carousel_layout', $jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
633 }
634 else{
635 echo YoutubeLayout::create_gallery_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
636
637 }
638
639 ?>
640 <!--
641 <?php foreach ($jsonResult->items as $item) : ?>
642 <?php
643 $privacyStatus = isset($item->status->privacyStatus) ? $item->status->privacyStatus : null;
644 $thumbnail = $this->get_thumbnail_url($item, $options['thumbnail'], $privacyStatus);
645 $vid = $this->get_id($item);
646 if (empty($gallobj->first_vid)) {
647 $gallobj->first_vid = $vid;
648 }
649 if ($privacyStatus == 'private' && $options['hideprivate']) {
650 continue;
651 }
652 ?>
653 <div class="item" data-vid="<?php echo $vid; ?>">
654 <div class="thumb" style="background: <?php echo "url({$thumbnail}) no-repeat center"; ?>">
655 <div class="play-icon">
656 <img src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS. 'images/youtube/youtube-play.png'); ?>" alt="">
657 </div>
658 </div>
659 <div class="body">
660 <p><?php echo $item->snippet->title; ?></p>
661 </div>
662 </div>
663
664 <?php endforeach; ?> -->
665
666 <div class="item" style="height: 0"></div>
667 </div>
668
669
670 <?php
671 $layout = $this->get_layout();
672
673 if ($totalPages > 1 && $layout !== 'carousel') : ?>
674 <div class="ep-youtube__content__pagination <?php echo (empty($prevPageToken) && empty($nextPageToken)) ? ' hide ' : ''; ?>">
675 <div
676 class="ep-prev" <?php echo empty($prevPageToken) ? ' style="display:none" ' : ''; ?>
677 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
678 data-pagetoken="<?php echo esc_attr($prevPageToken) ?>"
679 data-pagesize="<?php echo intval($options['pagesize']) ?>"
680 >
681 <span><?php _e("Prev", "embedpress"); ?></span>
682 </div>
683 <div class="is_desktop_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
684 <?php
685
686 $numOfPages = $totalPages;
687 $renderedEllipses = false;
688
689 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
690
691 for($i = 1; $i<=$numOfPages; $i++)
692 {
693 //render pages 1 - 3
694 if($i < 4) {
695 //render link
696 $is_current = $i == (int)$currentPage? "active__current_page" : "";
697
698 echo wp_kses_post("<span class='page-number $is_current' data-page='$i'>$i</span>");
699
700 }
701
702 //render current page number
703 else if($i == (int)$currentPage) {
704 //render link
705 echo wp_kses_post('<span class="page-number active__current_page" data-page="'.$i.'">'.$i.'</span>');
706 //reset ellipses
707 $renderedEllipses = false;
708 }
709
710 //last page number
711 else if ($i >= $numOfPages - 1) {
712 //render link
713 echo wp_kses_post('<span class="page-number" data-page="'.$i.'">'.$i.'</span>');
714 }
715
716 //make sure you only do this once per ellipses group
717 else {
718 if (!$renderedEllipses){
719 print("...");
720 $renderedEllipses = true;
721 }
722 }
723 }
724 ?>
725
726 </div>
727
728 <div class="is_mobile_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
729 <?php
730
731 $numOfPages = $totalPages;
732 $renderedEllipses = false;
733
734 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
735
736 for($i = 1; $i<=$numOfPages; $i++)
737 {
738
739 //render current page number
740 if($i == (int)$currentPage) {
741 //render link
742 echo wp_kses_post('<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
743 //reset ellipses
744 $renderedEllipses = false;
745 }
746
747 //last page number
748 else if ($i >= $numOfPages ) {
749 //render link
750 echo wp_kses_post('...<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
751 }
752 }
753 ?>
754
755 </div>
756
757
758 <div
759 class="ep-next " <?php echo empty($nextPageToken) ? ' style="display:none" ' : ''; ?>
760 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
761 data-pagetoken="<?php echo esc_attr($nextPageToken) ?>"
762 data-pagesize="<?php echo intval($options['pagesize']) ?>"
763 >
764 <span><?php _e("Next ", "embedpress"); ?> </span>
765 </div>
766 </div>
767 <?php endif; ?>
768
769 <div class="ep-loader-wrap">
770 <div class="ep-loader"><img alt="loading" src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS. 'images/youtube/spin.gif'); ?>"></div>
771 </div>
772
773 </div>
774 </div>
775
776 <?php
777 $gallobj->html = ob_get_clean();
778 else:
779 $gallobj->html = $this->clean_api_error_html(__("There is nothing on the playlist.", 'embedpress'));
780 endif;
781
782 return $gallobj;
783 }
784
785 public function get_api_key_error_message(){
786 return '<div>' . sprintf(__("EmbedPress: Please enter your YouTube API key at <a class='ep-link' href='%s' target='_blank' style='color: #5b4e96; text-decoration: none'>EmbedPress > Platforms > YouTube</a> to embed YouTube Channel.", "embedpress"), admin_url('?page=embedpress&page_type=youtube#api_key')) . '</div>';
787 }
788
789 public function get_id($item){
790 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
791 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
792 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
793 return $vid;
794 }
795 public function get_thumbnail_url($item, $quality, $privacyStatus) {
796 $url = "";
797 if ($privacyStatus == 'private') {
798 $url = EMBEDPRESS_URL_ASSETS. 'images/youtube/private.png';
799 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
800 $url = $item->snippet->thumbnails->{$quality}->url;
801 } elseif (isset($item->snippet->thumbnails->medium->url)) {
802 $url = $item->snippet->thumbnails->medium->url;
803 } elseif (isset($item->snippet->thumbnails->default->url)) {
804 $url = $item->snippet->thumbnails->default->url;
805 } elseif (isset($item->snippet->thumbnails->high->url)) {
806 $url = $item->snippet->thumbnails->high->url;
807 } else {
808 $url = EMBEDPRESS_URL_ASSETS. 'images/youtube/deleted-video-thumb.png';
809 }
810 return $url;
811 }
812
813 public function compare_vid_date($a, $b) {
814 if ($a->snippet->publishedAt == $b->snippet->publishedAt) {
815 return 0;
816 }
817 return ($a->snippet->publishedAt > $b->snippet->publishedAt) ? -1 : 1;
818 }
819
820 public function clean_api_error($raw_message) {
821 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
822 }
823
824 public function clean_api_error_html($raw_message) {
825 $clean_html = '';
826 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
827 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . $this->clean_api_error($raw_message) . '</div>';
828 }
829 return $clean_html;
830 }
831
832 /** inline {@inheritdoc} */
833 public function getFakeResponse() {
834 preg_match('~v=([a-z0-9_\-]+)~i', (string) $this->url, $matches);
835
836 $embedUrl = 'https://www.youtube.com/embed/' . $matches['1'] . '?feature=oembed';
837
838 $attr = [];
839 $attr[] = 'width="{width}"';
840 $attr[] = 'height="{height}"';
841 $attr[] = 'src="' . esc_url($embedUrl) . '"';
842 $attr[] = 'frameborder="0"';
843 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
844 $attr[] = 'allowfullscreen';
845
846 return [
847 'type' => 'video',
848 'provider_name' => 'Youtube',
849 'provider_url' => 'https://www.youtube.com',
850 'title' => 'Unknown title',
851 'html' => '<iframe ' . implode(' ', $attr) . '></iframe>',
852 ];
853 }
854
855 // public $num = 0;
856
857
858
859 public $x = 0;
860
861 public function styles($params, $url){
862
863 $uniqid = '.ose-youtube.ose-uid-'.md5($url);
864
865 ob_start();
866 ?>
867 <style>
868
869 <?php
870 $attributes_data = $params;
871
872 $is_pagination = 'flex';
873
874 $gap = '30';
875 $columns = '';
876
877 if (isset($attributes_data['ispagination']) && $attributes_data['ispagination']) {
878 $is_pagination = 'none';
879 }
880 if(isset($attributes_data['gapbetweenvideos'])){
881 $gap = $attributes_data['gapbetweenvideos'];
882 }
883 if(isset($attributes_data['columns'])){
884 $columns = $attributes_data['columns'];
885 }
886
887
888 if(!empty($columns) && (int) $columns > 0){
889 $repeatCol = 'repeat(auto-fit, minmax('.esc_html('calc('.(100 / (int) $columns).'% - '.$gap.'px)').', 1fr))';
890 }
891 else{
892 $repeatCol = 'repeat(auto-fit, minmax(calc(250px - '.$gap.'px), 1fr))';
893 }
894
895 ?>
896 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap:not(.youtube-carousel) {
897 gap: <?php echo esc_html($gap); ?>px !important;
898 margin-top: <?php echo esc_html($gap); ?>px !important;
899 grid-template-columns: <?php echo $repeatCol; ?>;
900 }
901 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .ep-youtube__content__pagination {
902 display: <?php echo esc_html($is_pagination); ?>!important;
903 }
904
905 <?php echo esc_attr($uniqid); ?> .layout-list .ep-youtube__content__block .youtube__content__body .content__wrap{
906 grid-template-columns: repeat(auto-fit, minmax(calc(100% - 30px), 1fr))!important;
907 }
908
909 @media (max-width: 420px) {
910 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap:not(.youtube-carousel) {
911 gap: 30px !important;
912 }
913 }
914
915 <?php
916 if($is_pagination){
917 echo esc_attr($uniqid) ?> {
918 height: 100%!important;
919 }
920 <?php
921 }
922 ?>
923 </style>
924 <?php
925 return ob_get_clean();
926 }
927 }
928