PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.33
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.33
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.33, at Layouts/Grid.php

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