PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.4.11
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.4.11
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 / GooglePhotos.php
embedpress / EmbedPress / Providers Last commit date
TemplateLayouts 5 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 3 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 3 months ago Wrapper.php 3 years ago X.php 2 years ago Youtube.php 5 months ago index.html 7 years ago
GooglePhotos.php
500 lines
1 <?php
2
3 namespace EmbedPress\Providers;
4
5 use EmbedPress\Includes\Classes\Helper;
6 use Embera\Provider\ProviderAdapter;
7 use Embera\Provider\ProviderInterface;
8 use Embera\Url;
9
10 (defined('ABSPATH') && defined('EMBEDPRESS_IS_LOADED')) or die("No direct script access allowed.");
11
12 class GooglePhotos extends ProviderAdapter implements ProviderInterface
13 {
14 protected static $hosts = ["photos.app.goo.gl", "photos.google.com"];
15 private $player_js = "https://cdn.jsdelivr.net/npm/publicalbum@1.3.4/embed-ui.min.js"; //EMBEDPRESS_URL_ASSETS . "js/embed-ui.min.js";
16 private $min_expiration = 0;
17 private $allowed_url_patttern = "/^https:\/\/photos\.app\.goo\.gl\/|^https:\/\/photos\.google\.com(?:\/u\/\d+)?\/share\//";
18
19 static public $name = "google-photos-album";
20
21 /** @var array Array with allowed params for the current Provider */
22 protected $allowedParams = [
23 'mode',
24 'maxwidth',
25 'google_photos_width',
26 'google_photos_height',
27 'maxheight',
28 'imageWidth',
29 'imageHeight',
30 'playerAutoplay',
31 'delay',
32 'repeat',
33 'mediaitemsAspectRatio',
34 'mediaitemsEnlarge',
35 'mediaitemsStretch',
36 'mediaitemsCover',
37 'backgroundColor',
38 'expiration',
39 'photos_link',
40 'showTitle',
41 ];
42
43
44 /** inline {@inheritdoc} */
45 protected $httpsSupport = true;
46
47 public function getAllowedParams()
48 {
49 return $this->allowedParams;
50 }
51
52 public function __construct($url, array $config = [])
53 {
54 parent::__construct($url, $config);
55 add_filter('embedpress_render_dynamic_content', [$this, 'fakeDynamicResponse'], 10, 2);
56 }
57
58 public function validateUrl(Url $url)
59 {
60 return preg_match('~^https:\/\/(photos\.app\.goo\.gl|photos\.google\.com)\/.*$~i', (string) $url);
61 }
62
63 public function get_embeded_content($link, $width = 0, $height = 480, $imageWidth = 1920, $imageHeight = 1080, $expiration = 60, $mode = 'gallery-player', $playerAutoplay = false, $delay = 5, $repeat = true, $aspectRatio = true, $enlarge = true, $stretch = true, $cover = false, $backgroundColor = '#000000', $photos_link = true, $showTitle = true)
64 {
65 if (is_object($link)) {
66 return $this->get_html($link, $expiration);
67 }
68
69
70 $props = $this->create_default_attr();
71 $props->link = $link;
72 $props->width = $width;
73 $props->height = $height;
74 $props->imageWidth = $imageWidth;
75 $props->imageHeight = $imageHeight;
76 $props->mode = $mode;
77 $props->slideshowAutoplay = $playerAutoplay;
78 $props->slideshowDelay = $delay;
79 $props->repeat = $repeat;
80 $props->backgroundColor = $backgroundColor;
81 $props->photos_link = $photos_link;
82 $props->showTitle = $showTitle;
83
84
85 $html = $this->get_html($props, $expiration);
86
87 return $html;
88 }
89
90 private function build_google_photos_html($props, $photos, $title = '')
91 {
92 $style = sprintf(
93 'display: none; width: %s; height: %s; max-width: 100%%;',
94 $props->width === 0 ? '100%' : ($props->width . 'px'),
95 $props->height === 0 ? '100%' : ($props->height . 'px')
96 );
97
98 $items_code = '';
99
100 if (in_array($props->mode, ['gallery-justify', 'gallery-masonary', 'gallery-grid'], true)) {
101 $items_code .= sprintf('<div class="photos-%s">', esc_attr($props->mode));
102 $counter = 0;
103
104 foreach ($photos as $photo) {
105 $preview_src = sprintf('%s=w%d-h%d', $photo, $props->imageWidth, $props->imageHeight);
106 $full_src = $photo . '=w2500';
107
108 $items_code .= sprintf(
109 '<div class="photo-item" data-item-number="%d" id="photo-%s">
110 <img data-photo-src="%s" src="%s" loading="lazy" alt="Photo"/>
111 </div>',
112 esc_attr($counter++),
113 md5($preview_src),
114 esc_url($full_src),
115 esc_url($preview_src)
116 );
117 }
118
119 $items_code .= '</div>';
120
121 return sprintf(
122 "<div class=\"google-photos-%s-widget\">%s%s</div>\n",
123 esc_attr($props->mode),
124 !empty($title) && (!isset($props->showTitle) || $props->showTitle) ? "<h3 style='text-align:left; margin: 22px 10px;'>" . esc_html($title) . "</h3>" : '',
125 $items_code
126 );
127 } else {
128 foreach ($photos as $photo) {
129 $preview_src = sprintf('%s=w%d-h%d', $photo, $props->imageWidth, $props->imageHeight);
130 $items_code .= sprintf('<object data="%s"></object>', esc_url($preview_src));
131 }
132 }
133
134 // Metadata for embedding
135 $attributes = [
136 'data-link' => $props->link,
137 'data-found' => count($photos),
138 'data-title' => $title,
139 'data-mediaitems-aspect-ratio' => true,
140 'data-mediaitems-enlarge' => '',
141 'data-mediaitems-stretch' => '',
142 'data-mediaitems-cover' => '',
143 'data-background-color' => $props->backgroundColor,
144 'data-photos-link' => isset($props->photos_link) ? ($props->photos_link ? 'true' : 'false') : 'true',
145 'data-show-title' => isset($props->showTitle) ? ($props->showTitle ? 'true' : 'false') : 'true',
146 ];
147
148 $attributes = apply_filters('embedpress_google_photos_attributes', $attributes, $props);
149
150 // Add external link icon if photos_link is enabled and mode is gallery-player or carousel
151 $external_link_html = '';
152
153 if (
154 isset($props->photos_link) &&
155 $props->photos_link &&
156 in_array($props->mode, ['gallery-player', 'carousel']) &&
157 $props->photos_link !== false
158 ) {
159 $external_link_html = sprintf(
160 '<a href="%s" target="_blank" rel="noopener noreferrer"
161 class="ep-google-photos-visit-btn"
162 style="position: absolute; top: 16px; right: 12px; background: rgb(0, 0, 0); color: white; border: none; border-radius: 50px; font-size: 12px; display: flex; align-items: center; justify-content: center; gap: 4px; z-index: 1000; text-decoration: none; width: 40px; height: 40px;">
163 <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
164 <path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
165 </svg>
166 </a>',
167 esc_url($props->link)
168 );
169 }
170
171 $attributes_string = '';
172 foreach ($attributes as $key => $value) {
173 if ($value !== null) {
174 $attributes_string .= sprintf(' %s="%s"', $key, $value);
175 }
176 }
177
178
179 return sprintf(
180 "<div class=\"pa-%s-widget\" style=\"%s\" %s>%s</div>%s\n",
181 esc_attr($props->mode),
182 $style,
183 $attributes_string,
184 $items_code,
185 $external_link_html
186 );
187 }
188
189 private function get_html($props, $expiration = 60)
190 {
191 $url_hash = md5($props->link);
192 $data_transient_key = sprintf('%s-data-%s', self::$name, $url_hash);
193 $option_expiration_key = sprintf('%s-expiration-%s', self::$name, $url_hash);
194
195 // Get cached data from transient
196 $data = get_transient($data_transient_key);
197
198 // Get previously stored expiration from options
199 $prev_expiration = get_option($option_expiration_key, 0);
200
201 $should_refresh = false;
202
203 // Refresh if no data or expiration changed
204 if (empty($data) || $prev_expiration != $expiration) {
205 $should_refresh = true;
206 }
207
208 if ($should_refresh) {
209 $contents = $this->get_remote_contents($props->link);
210 if (!$contents) {
211 return null;
212 }
213
214 $og = $this->parse_ogtags($contents);
215 $photos = $this->parse_photos($contents);
216
217 $data = [
218 'title' => $og['og:title'] ?? null,
219 'photos' => $photos,
220 ];
221
222 // Cache data transient with current expiration
223 set_transient($data_transient_key, $data, $expiration);
224
225 // Store current expiration persistently in options
226 update_option($option_expiration_key, $expiration);
227 }
228 return $this->build_google_photos_html($props, $data['photos'], $data['title']);
229 }
230
231
232 private function get_remote_contents($url)
233 {
234 if (preg_match($this->allowed_url_patttern, $url)) {
235 $response = wp_remote_get($url);
236 if (!is_wp_error($response)) {
237 return wp_remote_retrieve_body($response);
238 }
239 }
240 return null;
241 }
242
243 private function parse_ogtags($contents)
244 {
245 preg_match_all('~<\s*meta\s+property="(og:[^"]+)"\s+content="([^"]*)~i', $contents, $m);
246 $ogtags = [];
247 for ($i = 0; $i < count($m[1]); $i++) {
248 $ogtags[$m[1][$i]] = $m[2][$i];
249 }
250 return $ogtags;
251 }
252
253 private function parse_photos($contents)
254 {
255 preg_match_all('~\"(http[^"]+)\"\,[0-9^,]+\,[0-9^,]+~i', $contents, $m);
256 $photos = array_unique($m[1]);
257
258 // Use preg_replace_callback to remove width/height parameters directly in the matched URLs
259 return preg_replace_callback('/=[^&]+$/', function ($matches) {
260 return ''; // Remove the width/height parameters at the end
261 }, $photos);
262 }
263
264
265 private function get_embed_google_photos_html($props)
266 {
267 if ($contents = $this->get_remote_contents($props->link)) {
268 $og = $this->parse_ogtags($contents);
269 $title = $og['og:title'] ?? null;
270 $photos = $this->parse_photos($contents);
271
272
273 $style = sprintf(
274 'display: none; width: %s; height: %s; max-width: 100%%;',
275 $props->width === 0 ? '100%' : ($props->width . 'px'),
276 $props->height === 0 ? '100%' : ('100%')
277 );
278
279 $items_code = '';
280
281 if ($props->mode == 'gallery-justify' || $props->mode == 'gallery-masonary' || $props->mode == 'gallery-grid') {
282 $items_code .= sprintf('<div class="photos-%s">', esc_attr($props->mode));
283 $counter = 0;
284
285 foreach ($photos as $photo) {
286 // Preview image URL (small version for fast loading)
287 $preview_src = sprintf('%s=w%d-h%d', $photo, $props->imageWidth, $props->imageHeight);
288
289 // Full image URL (original size or any desired size)
290 $full_src = $photo . '=w2500';
291
292 // Add image items with preview and full image source
293 $items_code .= sprintf(
294 '<div class="photo-item" data-item-number="%d" id="photo-%s">
295 <img data-photo-src="%s" src="%s" loading="lazy" alt="Photo"/>
296 </div>',
297 esc_attr($counter++),
298 md5($preview_src),
299 esc_url($full_src), // Full image source for later use
300 esc_url($preview_src) // Preview image source for fast loading
301 );
302 }
303
304 $items_code .= '</div>';
305
306 return sprintf(
307 "<div class=\"google-photos-%s-widget\">%s%s</div>\n",
308 esc_attr($props->mode),
309 !empty($title) && (!isset($props->showTitle) || $props->showTitle) ? "<h3 style='text-align:left; margin: 22px 10px;'>" . esc_html($title) . "</h3>" : '',
310 $items_code
311 );
312 } else {
313 foreach ($photos as $photo) {
314 // Preview image URL (small version for fast loading)
315 $preview_src = sprintf('%s=w%d-h%d', $photo, $props->imageWidth, $props->imageHeight);
316
317 // Full image URL (original size or any desired size)
318 $full_src = $photo;
319
320 // Add image items with preview and full image source
321 $items_code .= sprintf(
322 '<object data="%s"></object>',
323 esc_url($preview_src) // Using preview image for non-gallery mode
324 );
325 }
326 }
327
328
329 $attributes = [
330 'data-link' => $props->link,
331 'data-found' => count($photos),
332 'data-title' => $title,
333 'data-mediaitems-aspect-ratio' => true,
334 'data-mediaitems-enlarge' => '',
335 'data-mediaitems-stretch' => '',
336 'data-mediaitems-cover' => '',
337 'data-background-color' => $props->backgroundColor,
338 ];
339
340 // Apply filter to allow modification of attributes
341 $attributes = apply_filters('embedpress_google_photos_attributes', $attributes, $props);
342
343 $attributes_string = '';
344 foreach ($attributes as $key => $value) {
345 if ($value !== null) {
346 $attributes_string .= sprintf(' %s="%s"', $key, $value);
347 }
348 }
349
350 return sprintf(
351 "<div class=\"pa-%s-widget\" style=\"%s\"%s>%s</div>\n",
352 esc_attr($props->mode),
353 $style,
354 $attributes_string,
355 $items_code
356 );
357 }
358 return null;
359 }
360
361 private function create_default_attr()
362 {
363 $props = new \stdClass();
364 $props->mode = 'gallery-player';
365 $props->width = 600;
366 $props->height = 450;
367 $props->imageWidth = 1920;
368 $props->imageHeight = 1080;
369 $props->slideshowAutoplay = false;
370 $props->slideshowDelay = 5;
371 $props->repeat = true;
372 $props->mediaitemsAspectRatio = true;
373 $props->mediaitemsEnlarge = true;
374 $props->mediaitemsStretch = true;
375 $props->mediaitemsCover = false;
376 $props->backgroundColor = '#000000';
377 $props->photos_link = true;
378 $props->showTitle = true;
379 return $props;
380 }
381
382 public function fakeDynamicResponse($html, $params)
383 {
384
385
386 $src_url = urldecode($params['url']);
387
388 $width = $params['width'] ?? 600;
389 $height = $params['height'] ?? 450;
390
391 $expiration = $params['expiration'] ?? 60;
392 $mode = $params['mode'] ?? 'carousel';
393 $playerAutoplay = isset($params['playerAutoplay']) ? Helper::getBooleanParam($params['playerAutoplay'], false) : false;
394 $showTitle = isset($params['showTitle']) ? Helper::getBooleanParam($params['showTitle'], true) : true;
395 $delay = $params['delay'] ?? 5;
396 $repeat = isset($params['repeat']) ? Helper::getBooleanParam($params['repeat'], true) : true;
397 $aspectRatio = isset($params['mediaitemsAspectRatio']) ? Helper::getBooleanParam($params['mediaitemsAspectRatio']) : false;
398 $enlarge = isset($params['mediaitemsEnlarge']) ? Helper::getBooleanParam($params['mediaitemsEnlarge']) : false;
399 $stretch = isset($params['mediaitemsStretch']) ? Helper::getBooleanParam($params['mediaitemsStretch']) : false;
400 $cover = isset($params['mediaitemsCover']) ? Helper::getBooleanParam($params['mediaitemsCover']) : false;
401 $backgroundColor = $params['backgroundColor'] ?? '#000000';
402
403 $photos_link = isset($params['photos_link']) ? Helper::getBooleanParam($params['photos_link']) : true;
404 $html = $this->get_embeded_content(
405 $src_url,
406 $width,
407 $height,
408 $width,
409 $height,
410 $expiration,
411 $mode,
412 $playerAutoplay,
413 $delay,
414 $repeat,
415 $aspectRatio,
416 $enlarge,
417 $stretch,
418 $cover,
419 $backgroundColor,
420 $photos_link,
421 $showTitle
422 );
423
424 // Conditionally load player JS only if mode is 'carousel' or autoplay is enabled
425 if ($mode === 'carousel' || $mode === 'gallery-player') {
426 $html .= '<script src="' . $this->player_js . '"></script>';
427 }
428 if ($mode === 'gallery-justify') {
429 wp_enqueue_script('embedpress-gallery-justify');
430 }
431 return $html;
432 }
433
434 public function fakeResponse()
435 {
436 $params = $this->getParams();
437
438 $src_url = urldecode($params['url']);
439
440 $width = $params['maxwidth'] ?? $params['width'] ?? 600;
441 $height = $params['maxheight'] ?? $params['height'] ?? 450;
442
443
444
445 $expiration = $params['expiration'] ?? 60;
446 $mode = $params['mode'] ?? 'carousel';
447 $playerAutoplay = isset($params['playerAutoplay']) ? Helper::getBooleanParam($params['playerAutoplay']) : false;
448 $delay = $params['delay'] ?? 5;
449 $repeat = isset($params['repeat']) ? Helper::getBooleanParam($params['repeat']) : false;
450 $aspectRatio = isset($params['mediaitemsAspectRatio']) ? Helper::getBooleanParam($params['mediaitemsAspectRatio']) : false;
451 $enlarge = isset($params['mediaitemsEnlarge']) ? Helper::getBooleanParam($params['mediaitemsEnlarge']) : false;
452 $stretch = isset($params['mediaitemsStretch']) ? Helper::getBooleanParam($params['mediaitemsStretch']) : false;
453 $cover = isset($params['mediaitemsCover']) ? Helper::getBooleanParam($params['mediaitemsCover']) : false;
454 $backgroundColor = $params['backgroundColor'] ?? '#000000';
455 $photos_link = isset($params['photos_link']) ? Helper::getBooleanParam($params['photos_link'], true) : true;
456 $showTitle = isset($params['showTitle']) ? Helper::getBooleanParam($params['showTitle'], true) : true;
457
458 $html = $this->get_embeded_content(
459 $src_url,
460 $width,
461 $height,
462 $width,
463 $height,
464 $expiration,
465 $mode,
466 $playerAutoplay,
467 $delay,
468 $repeat,
469 $aspectRatio,
470 $enlarge,
471 $stretch,
472 $cover,
473 $backgroundColor,
474 $photos_link,
475 $showTitle
476 );
477
478 // Conditionally load player JS only if mode is 'carousel' or autoplay is enabled
479 if ($mode === 'carousel' || $mode === 'gallery-player') {
480 $html .= '<script src="' . $this->player_js . '"></script>';
481 }
482 if ($mode === 'gallery-justify') {
483 wp_enqueue_script('embedpress-gallery-justify');
484 }
485
486 return [
487 'type' => 'rich',
488 'provider_name' => 'Google Photos',
489 'provider_url' => 'https://photos.app.goo.gl',
490 'title' => $params['title'] ?? 'Unknown title',
491 'html' => $html,
492 ];
493 }
494
495 public function modifyResponse(array $response = [])
496 {
497 return $this->fakeResponse();
498 }
499 }
500