PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.36
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.36
3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 2.44 All 141 releases
photonic / Layouts / Grid.php

Grid.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.36, at Layouts/Grid.php

627 lines 24.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Photonic_Plugin\Layouts;
4
5 use Photonic_Plugin\Components\Album_List;
6 use Photonic_Plugin\Components\Grid_Anchor;
7 use Photonic_Plugin\Components\Grid_Figure;
8 use Photonic_Plugin\Components\Grid_Image;
9 use Photonic_Plugin\Components\Pagination;
10 use Photonic_Plugin\Components\Photo_List;
11 use Photonic_Plugin\Core\Photonic;
12 use Photonic_Plugin\Layouts\Features\Can_Use_Lightbox;
13 use Photonic_Plugin\Platforms\Base;
14 use Photonic_Plugin\Components\Album;
15 use Photonic_Plugin\Components\Photo;
16
17 require_once 'Level_One_Gallery.php';
18 require_once 'Level_Two_Gallery.php';
19
20 require_once PHOTONIC_PATH . '/Components/Grid_Image.php';
21
22 require_once 'Features/Can_Use_Lightbox.php';
23
24 /**
25 * Class Grid
26 * This is the generic Grid layout for Photonic. This handles all grids except for slideshows. The following approaches are used for layouts:
27 * - CSS: Used for square, circle, masonry and justified grids (only when all images have sizes - pretty much every case except Instagram or SmugMug / Zenfolio galleries with missing thumbnails)
28 * - JS: Used for justified grids (only when at least one image is missing a size, e.g. Instagram with all sizes missing, or SmugMug with missing album thumbnails) and Mosaic
29 * The Justified Grid CSS approach is based on the solution provided here: https://stackoverflow.com/a/49107319
30 *
31 * @package Photonic_Plugin\Layouts
32 */
33 class Grid extends Core_Layout implements Level_One_Gallery, Level_Two_Gallery {
34 use Can_Use_Lightbox;
35
36 /**
37 * Generates the HTML for the lowest level gallery, i.e. the photos. This is used for local, modal and template displays.
38 * The code for the random layouts is handled in JS, but just the HTML markers for it are provided here.
39 *
40 * @param Photo_List $photo_list
41 * @param array $short_code
42 * @param $module Base
43 * @return string
44 */
45 public function generate_level_1_gallery(Photo_List $photo_list, array $short_code, Base $module): string {
46 $module->push_to_stack('Generate level 1 gallery');
47
48 $short_code = array_merge($this->common_parameters, $short_code);
49
50 $photos = $photo_list->photos;
51
52 $lightbox = self::get_lightbox();
53
54 $layout = $short_code['layout'];
55 $columns = sanitize_text_field(!empty($short_code['columns']) && ('random' !== $layout && 'mosaic' !== $layout) ? $short_code['columns'] : 'auto');
56 $more = !empty($short_code['more']) ? sanitize_text_field($short_code['more']) : '';
57 $more = (empty($more) && !empty($short_code['photo_more'])) ? sanitize_text_field($short_code['photo_more']) : $more;
58 $title_position = empty($short_code['title_position']) ? $photo_list->title_position : sanitize_text_field($short_code['title_position']);
59 $row_constraints = $photo_list->row_constraints;
60 $pagination = $photo_list->pagination;
61 $indent = $photo_list->indent;
62
63 $display = sanitize_text_field(!empty($short_code['display']) ? $short_code['display'] : 'local');
64 $panel = !empty($short_code['panel']) ? sanitize_text_field($short_code['panel']) : '';
65 $parent = $photo_list->parent;
66
67 list($container_start_id, $container_end_id) = $this->get_container_details($short_code, $module);
68 $non_standard = in_array($layout, ['random', 'masonry', 'masonry-horizontal', 'mosaic'], true);
69 $gallery_column_class = $this->get_gallery_column_class($non_standard, $columns, $row_constraints);
70 $effect = esc_attr($this->get_thumbnail_effect($short_code, $layout, $title_position));
71
72 $gallery_figure_classes = ['photonic-level-1', 'photonic-thumb'];
73
74 $lightbox_attributes = $lightbox->get_gallery_attributes($panel, $module); // Function returns escaped values
75 $anchor_classes = $lightbox_attributes['class'] ?: [];
76 $anchor_rel = $lightbox_attributes['rel'] ?: [];
77 $anchor_lightbox_data = $lightbox_attributes['specific'] ?: [];
78
79 $ret = '';
80
81 global $photonic_external_links_in_new_tab;
82 if (!empty($photonic_external_links_in_new_tab)) {
83 $target = " target='_blank' ";
84 $anchor_lightbox_data['target'] = '_blank';
85 }
86 else {
87 $target = '';
88 }
89
90 $counter = 0;
91
92 $layout_engine = $this->get_layout_engine($module, $short_code);
93 $all_sizes_present = strtolower($layout_engine) === 'css';
94
95 $grid_figures = [];
96
97 /** @var Photo $photo */
98 foreach ($photos as $idx => $photo) {
99 $counter++;
100
101 $figure_data = [];
102 if ('masonry-horizontal' === $layout) {
103 $figure_data['data-photonic-idx'] = $idx;
104 }
105
106 $additional_image_data = [];
107 $styles = [];
108 if ($non_standard && 'local' === $display) {
109 $thumb = $photo->tile_image ?: $photo->main_image;
110 if (!empty($photo->tile_size)) {
111 $inbuilt_sizes = $photo->tile_size;
112 }
113 elseif (!empty($photo->main_size)) {
114 $inbuilt_sizes = $photo->main_size;
115 }
116 }
117 else {
118 $thumb = $photo->thumbnail;
119 if (!empty($photo->thumb_size)) {
120 $inbuilt_sizes = $photo->thumb_size;
121 }
122 }
123
124 if (!empty($inbuilt_sizes)) {
125 if ('random' === $layout) {
126 $styles['--dw'] = $inbuilt_sizes['w'];
127 $styles['--dh'] = $inbuilt_sizes['h'];
128 }
129 }
130 else {
131 $all_sizes_present = false;
132 }
133
134 $deep_value = 'gallery[photonic-' . $module->provider . '-' . $parent . '-' . ($panel ?: $module->gallery_index) . ']/' . ($photo->id ?: $counter) . '/';
135 $additional_image_data['data-photonic-deep'] = esc_attr($deep_value);
136
137 if (!empty($photo->buy_link) && $module->show_buy_link) {
138 $additional_image_data['data-photonic-buy'] = esc_url($photo->buy_link);
139 }
140
141 $title = wp_kses_post($photo->title);
142 $description = wp_kses_post($photo->description);
143 $alt = wp_kses_post($photo->alt_title);
144
145 $titles = [
146 'title' => $title,
147 'desc' => $description,
148 'alt' => $alt,
149 ];
150
151 $title = $this->get_title($title, $titles, $short_code);
152
153 $title_markup = $lightbox->get_lightbox_title($photo, $module, $title, $alt, $target);
154 $additional_image_data['data-title'] = $title_markup;
155
156 $shown_title = '';
157 if (in_array($title_position, ['below', 'hover-slideup-show', 'hover-slidedown-show', 'slideup-stick'], true) && !empty($title)) {
158 // Convoluted... we want to remove any funky markup from $title, so wp_filter_nohtml_kses is used. But that does an `addslashes`, which causes more funky markup. So we use stripslashes, but then we decode the special characters.
159 // $shown_title = '<figcaption class="photonic-title-info"><div class="photonic-photo-title photonic-title">' . wp_specialchars_decode(stripslashes(wp_filter_nohtml_kses($title)), ENT_QUOTES) . '</div></figcaption>';
160 $shown_title = '<figcaption class="photonic-title-info"><div class="photonic-photo-title photonic-title">' . wp_specialchars_decode(stripslashes(wp_kses($title, Photonic::$safe_description_tags)), ENT_QUOTES) . '</div></figcaption>';
161 }
162
163 $photo_data = ['title' => $title_markup, 'deep' => $deep_value, 'raw_title' => esc_attr($title)];
164 if (!empty($photo->download)) {
165 $photo_data['download'] = esc_url($photo->download);
166 }
167 if (!empty($photo->video)) {
168 $photo_data['video'] = esc_url($photo->video);
169 $photo_data['poster'] = esc_url($photo->main_image);
170 }
171 else {
172 $photo_data['image'] = esc_url($photo->main_image);
173 }
174 $photo_data['id'] = $photo->id;
175 $photo_data['thumbnail'] = $thumb;
176
177 if (!empty($photo->main_size)) {
178 $photo_data['width'] = $photo->main_size['w'];
179 $photo_data['height'] = $photo->main_size['h'];
180 }
181
182 $image_lightbox_data = $lightbox->get_photo_attributes($photo_data, $module);
183
184 if ('tooltip' === $title_position) {
185 $additional_image_data['data-photonic-tooltip'] = esc_attr($title);
186 }
187
188 $grid_image = new Grid_Image();
189 $grid_image->alt = esc_attr($alt ?: wp_kses_post($photo->title)); // alt and title are the same for everything except WP galleries. This has been put in for cases where users don't specify an alt on WP galleries.
190 $grid_image->src = $thumb;
191 $grid_image->classes = [sanitize_html_class($layout)];
192 $grid_image->dimensions = $inbuilt_sizes ?? [];
193
194 $grid_anchor = new Grid_Anchor();
195 $grid_anchor->href = $lightbox->get_grid_link($photo, $short_code, $module); // CANNOT esc_url $lightbox->get_grid_link(...), since it sometimes returns a URL, and sometimes a "#" location. Instead, within get_grid_link there is either esc_attr or esc_url
196 $grid_anchor->classes = $anchor_classes;
197 $grid_anchor->rel = $anchor_rel;
198 $grid_anchor->data = array_merge(
199 $anchor_lightbox_data,
200 $image_lightbox_data,
201 $additional_image_data
202 );
203 $grid_anchor->title = 'none' !== $title_position ? esc_attr($title) : '';
204 $grid_anchor->figcaption = $shown_title;
205 $grid_anchor->image = $grid_image;
206 $grid_anchor->indent = $indent;
207
208 $grid_figure = new Grid_Figure();
209 $grid_figure->classes = $gallery_figure_classes;
210 $grid_figure->styles = $styles;
211 $grid_figure->data = $figure_data;
212 $grid_figure->video_markup = $lightbox->get_video_markup($photo, $module, $indent);
213 $grid_figure->anchor = $grid_anchor;
214 $grid_figure->indent = $indent;
215
216 $grid_figures[] = $grid_figure;
217 }
218
219 if (!empty($grid_figures)) {
220 $this->set_lazy_loading_attributes($all_sizes_present, $grid_figures);
221
222 $container_class_list = $this->get_common_gallery_classes(1, $title_position, $non_standard, $layout, $effect, $all_sizes_present, $gallery_column_class, $display);
223 $container_class_list[] = $lightbox->get_container_classes();
224
225 $data_query = $this->get_updated_data_query($short_code, $pagination);
226 $container_data_attributes = [
227 'data-photonic-platform' => esc_attr($module->provider),
228 'data-photonic-gallery-columns' => esc_attr($columns),
229 'data-photonic-query' => esc_attr($data_query),
230 ];
231
232 if ('masonry-horizontal' === $layout) {
233 $container_data_attributes['data-photonic-max-idx'] = count($photos);
234 }
235
236 $ret = $this->generate_container_markup($module, $pagination, $container_class_list, $container_data_attributes, $grid_figures, $container_start_id, $container_end_id, $more, 1, $indent);
237 }
238
239 $module->pop_from_stack();
240 return $ret;
241 }
242
243 /**
244 * Generates the HTML for a group of level-2 items, i.e. Photosets (Albums) and Galleries for Flickr, Albums for Google Photos,
245 * Albums for SmugMug, and Photosets (Galleries and Collections) for Zenfolio. No concept of albums
246 * exists in native WP and Instagram.
247 *
248 * @param Album_List $album_list
249 * @param array $short_code
250 * @param Base $module
251 * @return string
252 */
253 public function generate_level_2_gallery(Album_List $album_list, array $short_code, Base $module): string {
254 $module->push_to_stack('Generate Level 2 Gallery');
255
256 $short_code = array_merge($this->common_parameters, $short_code);
257
258 $objects = $album_list->albums;
259
260 $layout = esc_attr($short_code['layout'] ?? 'square');
261 $columns = $short_code['columns'];
262 $more = !empty($short_code['more']) ? esc_attr($short_code['more']) : '';
263 $title_position = esc_attr(empty($short_code['title_position']) ? $album_list->title_position : $short_code['title_position']);
264 $row_constraints = $album_list->row_constraints;
265 $pagination = $album_list->pagination;
266 $indent = $album_list->indent;
267
268 $singular_type = esc_attr($album_list->singular_type);
269 $level_1_count_display = $album_list->level_1_count_display;
270 $provider = esc_attr($module->provider);
271
272 $gallery_data = array_merge(
273 [
274 'platform' => $provider,
275 'singular' => $singular_type,
276 'popup' => esc_attr($short_code['popup']),
277 ],
278 $album_list->gallery_attributes
279 );
280
281 list($container_start_id, $container_end_id) = $this->get_container_details($short_code, $module);
282 $non_standard = in_array($layout, ['random', 'masonry', 'masonry-horizontal', 'mosaic'], true);
283 $gallery_column_class = $this->get_gallery_column_class($non_standard, $columns, $row_constraints);
284 $effect = esc_attr($this->get_thumbnail_effect($short_code, $layout, $title_position));
285
286 $gallery_figure_classes = ['photonic-level-2', 'photonic-thumb'];
287
288 $gallery_anchor_classes = ['photonic-level-2-thumb'];
289 if ($album_list->album_opens_gallery) {
290 $gallery_anchor_classes[] = 'gallery-page';
291 }
292
293 $layout_engine = $this->get_layout_engine($module, $short_code);
294 $all_sizes_present = strtolower($layout_engine) === 'css';
295
296 $ret = '';
297 $grid_figures = [];
298
299 /** @var Album $object */
300 foreach ($objects as $idx => $object) {
301 $data_attributes = $object->data_attributes ?: [];
302 $styles = [];
303
304 $figure_data = [];
305 if ('masonry-horizontal' === $layout) {
306 $figure_data['data-photonic-idx'] = $idx;
307 }
308
309 $anchor_data = [];
310 foreach ($data_attributes as $attr => $value) {
311 $anchor_data['data-photonic-' . $attr] = $value;
312 }
313
314 $id = empty($object->id) ? '' : $object->id . '-';
315 $id = esc_attr($id . $module->gallery_index);
316 $title = wp_kses_post($object->title);
317
318 $anchor_data['data-title'] = esc_attr($title);
319
320 if ('tooltip' === $title_position) {
321 $anchor_data['data-photonic-tooltip'] = esc_attr($title);
322 }
323
324 if ($non_standard && !empty($object->tile_image)) {
325 $img_src = $object->tile_image;
326 $inbuilt_sizes = $object->tile_size ?: [];
327 }
328 else {
329 $img_src = $object->thumbnail;
330 $inbuilt_sizes = $object->thumb_size ?: [];
331 }
332
333 if (!empty($inbuilt_sizes)) {
334 if ('random' === $layout) {
335 $styles['--dw'] = $inbuilt_sizes['w'];
336 $styles['--dh'] = $inbuilt_sizes['h'];
337 }
338 }
339 else {
340 $all_sizes_present = false;
341 }
342
343 $shown_title = '';
344 if (in_array($title_position, ['below', 'hover-slideup-show', 'hover-slidedown-show', 'slideup-stick'], true)) {
345 $shown_title = "\n$indent\t\t\t<figcaption class='photonic-title-info'>\n$indent\t\t\t\t<div class='photonic-$singular_type-title photonic-title'>" . wp_specialchars_decode(stripslashes(wp_filter_nohtml_kses($title)), ENT_QUOTES);
346 if (!$level_1_count_display && !empty($object->counter)) {
347 $shown_title .= '<span class="photonic-title-photo-count photonic-' . $singular_type . '-photo-count">' . sprintf(esc_html__('%s photos', 'photonic'), $object->counter) . '</span>';
348 }
349 $shown_title .= "</div>\n$indent\t\t\t</figcaption>";
350 }
351
352 $grid_image = new Grid_Image();
353 $grid_image->alt = esc_attr($title);
354 $grid_image->src = esc_url($img_src);
355 $grid_image->classes = [sanitize_html_class($layout)];
356 $grid_image->dimensions = $inbuilt_sizes ?? [];
357
358 $grid_anchor = new Grid_Anchor();
359 $grid_anchor->id = "photonic-$provider-$singular_type-thumb-$id";
360 $grid_anchor->href = esc_url($object->gallery_url ?? $object->main_page);
361 $grid_anchor->classes = array_merge($gallery_anchor_classes, $object->classes);
362 $grid_anchor->data = $anchor_data;
363 $grid_anchor->title = 'none' !== $title_position ? esc_attr($title) : '';
364 $grid_anchor->figcaption = $shown_title;
365 $grid_anchor->image = $grid_image;
366 $grid_anchor->indent = $indent;
367
368 $grid_figure = new Grid_Figure();
369 $grid_figure->id = "photonic-$provider-$singular_type-$id";
370 $grid_figure->classes = $gallery_figure_classes;
371 $grid_figure->styles = $styles;
372 $grid_figure->data = $figure_data;
373 $grid_figure->anchor = $grid_anchor;
374 $grid_figure->indent = $indent;
375 $grid_figure->prompter_markup = $this->get_password_prompter($object, $provider, $singular_type, $id);
376
377 $grid_figures[] = $grid_figure;
378 }
379
380 if (!empty($grid_figures)) {
381 $this->set_lazy_loading_attributes($all_sizes_present, $grid_figures);
382 $gallery_class_list = $this->get_common_gallery_classes(2, $title_position, $non_standard, $layout, $effect, $all_sizes_present, $gallery_column_class);
383
384 $data_query = $this->get_updated_data_query($short_code, $pagination);
385 $container_data_attributes = [
386 'data-photonic-platform' => $provider,
387 'data-photonic-gallery-columns' => esc_attr($columns),
388 'data-photonic-query' => esc_attr($data_query),
389 'data-photonic' => esc_attr(wp_json_encode($gallery_data)),
390 ];
391
392 $ret = $this->generate_container_markup($module, $pagination, $gallery_class_list, $container_data_attributes, $grid_figures, $container_start_id, $container_end_id, $more, 2, $indent);
393 }
394
395 $module->pop_from_stack();
396 return $ret;
397 }
398
399 /**
400 * @param array $short_code
401 * @param Base $module
402 * @return array
403 */
404 private function get_container_details(array $short_code, Base $module): array {
405 if ('modal' !== $short_code['display']) {
406 $start_id = "photonic-" . esc_attr($module->provider) . "-stream-" . esc_attr($module->gallery_index) . "-container";
407 $end_id = "photonic-" . esc_attr($module->provider) . "-stream-" . esc_attr($module->gallery_index) . "-container-end";
408 }
409 else {
410 $start_id = "photonic-" . esc_attr($module->provider) . "-panel-" . esc_attr(sanitize_text_field($short_code['panel'])) . "-container";
411 $end_id = "photonic-" . esc_attr($module->provider) . "-panel-" . esc_attr(sanitize_text_field($short_code['panel'])) . "-container-end";
412 }
413 return [$start_id, $end_id];
414 }
415
416 /**
417 * @param array $short_code
418 * @param Pagination $pagination
419 * @return string
420 */
421 private function get_updated_data_query(array $short_code, Pagination $pagination): string {
422 $to_be_glued = '';
423
424 if (!empty($short_code)) {
425 $to_be_glued = [];
426 foreach ($short_code as $name => $value) {
427 if (is_scalar($value)) {
428 if ('next_token' !== $name) {
429 $to_be_glued[] = $name . '=' . $value;
430 }
431 }
432 }
433
434 if (!empty($pagination->next_token)) {
435 $to_be_glued[] = 'next_token=' . $pagination->next_token;
436 }
437
438 $to_be_glued = implode('&', $to_be_glued);
439 $to_be_glued = esc_attr($to_be_glued);
440 }
441 return $to_be_glued;
442 }
443
444 /**
445 * Returns the thumbnail effect that should be used for a gallery. Not all effects can be used by all types of layouts.
446 *
447 * @param $short_code
448 * @param $layout
449 * @param $title_position
450 * @return string
451 */
452 private function get_thumbnail_effect($short_code, $layout, $title_position): string {
453 if (!empty($short_code['thumbnail_effect'])) {
454 $effect = $short_code['thumbnail_effect'];
455 }
456 else {
457 global $photonic_standard_thumbnail_effect, $photonic_justified_thumbnail_effect, $photonic_mosaic_thumbnail_effect, $photonic_masonry_thumbnail_effect;
458 $effect = 'mosaic' === $layout ? $photonic_mosaic_thumbnail_effect :
459 (('masonry' === $layout || 'masonry-horizontal' === $layout)? $photonic_masonry_thumbnail_effect :
460 ('random' === $layout ? $photonic_justified_thumbnail_effect :
461 $photonic_standard_thumbnail_effect));
462 $effect = esc_attr($effect);
463 }
464
465 if ('circle' === $layout && 'opacity' !== $effect) { // "Zoom" doesn't work for circle
466 $thumbnail_effect = 'none';
467 }
468 elseif (('square' === $layout || 'launch' === $layout || 'masonry' === $layout) && 'below' === $title_position) { // For these combinations, Zoom doesn't work
469 $thumbnail_effect = 'none';
470 }
471 else {
472 $thumbnail_effect = $effect;
473 }
474 return apply_filters('photonic_thumbnail_effect', $thumbnail_effect, $short_code, $layout, $title_position);
475 }
476
477 /**
478 * Returns the layout engine to be used, i.e. js or css.
479 *
480 * @param Base $module
481 * @param $short_code
482 * @return string
483 */
484 private function get_layout_engine(Base $module, $short_code): string {
485 $layout_engine = 'photonic_' . $module->provider . '_layout_engine';
486 global ${$layout_engine};
487 return $short_code['layout_engine'] ?? ${$layout_engine};
488 }
489
490 /**
491 * @param Album $object
492 * @param string $provider
493 * @param string $singular_type
494 * @param string $id
495 * @return string
496 */
497 private function get_password_prompter(Album $object, string $provider, string $singular_type, string $id): string {
498 $password_prompt = '';
499 if (!empty($object->passworded)) {
500 $password_prompt = "
501 <div class='photonic-password-prompter' id='photonic-$provider-$singular_type-prompter-$id' title='$this->prompt_title' data-photonic-prompt='password'>
502 <div class='photonic-password-prompter-content'>
503 <div class='photonic-prompt-head'>
504 <h3>
505 <span class='title'>$this->prompt_title</span>
506 <button class='close'>&times;</button>
507 </h3>
508 </div>
509 <div class='photonic-prompt-body'>
510 <p>$this->prompt_text</p>
511 <input type='password' name='photonic-$provider-password' />
512 <button class='photonic-$provider-submit photonic-password-submit confirm'>$this->prompt_submit</button>
513 </div>
514 </div>
515 </div>";
516 }
517 return $password_prompt;
518 }
519
520 /**
521 * @param bool $all_sizes_present
522 * @param array $grid_figures
523 */
524 private function set_lazy_loading_attributes(bool $all_sizes_present, array $grid_figures): void {
525 if ($all_sizes_present) {
526 /** @var Grid_Figure $figure */
527 foreach ($grid_figures as $figure) {
528 $figure->anchor->image->lazy_load = 'lazy';
529 $figure->anchor->image->src_attr = 'data-src';
530 }
531 }
532 else {
533 /** @var Grid_Figure $figure */
534 foreach ($grid_figures as $figure) {
535 $figure->anchor->image->lazy_load = 'eager';
536 $figure->anchor->image->src_attr = 'src';
537 }
538 }
539 }
540
541 private function get_common_gallery_classes($level, $title_position, $non_standard, $layout, $thumbnail_effect, $all_sizes_present, $gallery_column_class, $display = null): array {
542 $classes = [
543 'title-display-' . $title_position,
544 'photonic-level-' . $level . '-container',
545 $all_sizes_present ? 'sizes-present' : 'sizes-missing',
546 $gallery_column_class,
547 ];
548
549 if ('modal' === $display) {
550 $classes[] = 'modal-gallery';
551 }
552 else {
553 $classes[] = $non_standard ? 'photonic-' . $layout . '-layout' : 'photonic-standard-layout';
554 $classes[] = 'photonic-thumbnail-effect-' . $thumbnail_effect;
555 }
556
557 return $classes;
558 }
559
560 /**
561 * @param bool $non_standard
562 * @param string $columns
563 * @param array $row_constraints
564 * @return string
565 */
566 private function get_gallery_column_class(bool $non_standard, string $columns, array $row_constraints): string {
567 $gallery_column_class = '';
568 if (!$non_standard) {
569 if (absint($columns)) {
570 $gallery_column_class = 'photonic-gallery-' . esc_attr($columns) . 'c';
571 }
572 elseif ('padding' === $row_constraints['constraint-type']) {
573 $gallery_column_class = 'photonic-auto-padded';
574 }
575 elseif (!empty($row_constraints['count'])) {
576 $gallery_column_class = 'photonic-gallery-' . esc_attr($row_constraints['count']) . 'c';
577 }
578 }
579 return $gallery_column_class;
580 }
581
582 private function glue_data_attributes(array $map): string {
583 $data_pieces = [];
584 if (!empty($map)) {
585 $data_pieces = array_map(
586 function (string $key, string $value): string {
587 return $key . '="' . $value . '"';
588 },
589 array_keys($map),
590 array_values($map)
591 );
592 }
593 return implode(' ', $data_pieces);
594 }
595
596 private function generate_container_markup(Base $module, Pagination $pagination, array $container_class_list, array $container_data_attributes, array $grid_figures, string $start_id, string $end_id, string $more, int $level, string $indent): string {
597 $ret = '';
598 if (!empty($grid_figures)) {
599 $container_class = str_replace(' ', ' ', trim(implode(' ', $container_class_list)));
600
601 $style = '';
602 if (in_array('photonic-random-layout', $container_class_list, true)) {
603 global $photonic_tile_min_height;
604 if (!is_numeric($photonic_tile_min_height)) {
605 $photonic_tile_min_height = 200;
606 }
607 $photonic_tile_min_height = esc_attr($photonic_tile_min_height);
608 $style = "style='--tile-min-height: {$photonic_tile_min_height}px'";
609 }
610
611 $container_data_string = $this->glue_data_attributes($container_data_attributes);
612 $ret = "\n$indent<div id='" . esc_attr($start_id) . "' class='" . esc_attr($container_class) . "' $container_data_string $style>\n";
613 foreach ($grid_figures as $figure) {
614 $ret .= $figure->html($module, $this, false);
615 }
616
617 $ret .= "\n$indent</div> <!-- ./photonic-level-$level-container -->";
618 $ret .= "\n$indent<span id='$end_id'></span>";
619
620 if ($pagination->end > -1 && $pagination->total > -1 && $pagination->total > $pagination->end) {
621 $ret .= !empty($more) ? "\n$indent<a href='#' class='photonic-more-button photonic-more-dynamic'>$more</a>\n" : '';
622 }
623 }
624 return $ret;
625 }
626 }
627