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
← All changes | Layouts/Grid.php +455 -499 2.413.36 View file →
@@ -1,95 +1,88 @@
1 1 <?php
2 +
2 3 namespace Photonic_Plugin\Layouts;
3 4
4 -use Photonic_Plugin\Modules\Core;
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;
5 16
6 -require_once('Level_One_Gallery.php');
7 -require_once('Level_Two_Gallery.php');
17 +require_once 'Level_One_Gallery.php';
18 +require_once 'Level_Two_Gallery.php';
8 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 + */
9 33 class Grid extends Core_Layout implements Level_One_Gallery, Level_Two_Gallery {
10 - private static $instance = null;
34 + use Can_Use_Lightbox;
11 35
12 - public static function get_instance() {
13 - if (self::$instance == null) {
14 - self::$instance = new Grid();
15 - }
16 - return self::$instance;
17 - }
18 -
19 36 /**
20 - * Generates the HTML for the lowest level gallery, i.e. the photos. This is used for both, in-page and popup displays.
37 + * Generates the HTML for the lowest level gallery, i.e. the photos. This is used for local, modal and template displays.
21 38 * The code for the random layouts is handled in JS, but just the HTML markers for it are provided here.
22 39 *
23 - * @param $photos
24 - * @param array $options
25 - * @param $short_code
26 - * @param $module Core
40 + * @param Photo_List $photo_list
41 + * @param array $short_code
42 + * @param $module Base
27 43 * @return string
28 44 */
29 - function generate_level_1_gallery($photos, $options, $short_code, $module) {
45 + public function generate_level_1_gallery(Photo_List $photo_list, array $short_code, Base $module): string {
30 46 $module->push_to_stack('Generate level 1 gallery');
31 47
32 - $layout = $short_code['layout'];
33 - $columns = !empty($short_code['columns']) && ($layout !== 'random' && $layout !== 'mosaic') ? $short_code['columns'] : 'auto';
34 - $display = !empty($short_code['display']) ? $short_code['display'] : 'in-page';
35 - $more = !empty($short_code['more']) ? esc_attr($short_code['more']) : '';
36 - $more = (empty($more) && !empty($short_code['photo_more'])) ? esc_attr($short_code['photo_more']) : $more;
37 - $panel = !empty($short_code['panel']) ? $short_code['panel'] : '';
48 + $short_code = array_merge($this->common_parameters, $short_code);
38 49
39 - $title_position = empty($short_code['title_position']) ? $options['title_position'] : $short_code['title_position'];
40 - $row_constraints = isset($options['row_constraints']) && is_array($options['row_constraints']) ? $options['row_constraints'] : [];
41 - $sizes = isset($options['sizes']) && is_array($options['sizes']) ? $options['sizes'] : [];
42 - $show_lightbox = !isset($options['show_lightbox']) ? true: $options['show_lightbox'];
43 - $type = !empty($options['type']) ? $options['type'] : 'photo';
44 - $parent = !empty($options['parent']) ? $options['parent'] : 'stream';
45 - $pagination = isset($options['level_2_meta']) && is_array($options['level_2_meta']) ? $options['level_2_meta'] : [];
46 - $indent = !isset($options['indent']) ? "\t" : $options['indent'];
50 + $photos = $photo_list->photos;
47 51
48 - list($container_id, $container_end) = $this->get_container_details($short_code, $module);
52 + $lightbox = self::get_lightbox();
49 53
50 - $non_standard = $layout == 'random' || $layout == 'masonry' || $layout == 'mosaic';
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;
51 62
52 - $col_class = '';
53 - if (absint($columns)) {
54 - $col_class = 'photonic-gallery-'.$columns.'c';
55 - }
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;
56 66
57 - if ($col_class == '' && $row_constraints['constraint-type'] == 'padding') {
58 - $col_class = 'photonic-pad-photos';
59 - }
60 - else if ($col_class == '') {
61 - $col_class = 'photonic-gallery-'.$row_constraints['count'].'c';
62 - }
63 - $col_class .= ' photonic-level-1 photonic-thumb photonic-thumb-'.$layout;
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));
64 71
65 - $link_attributes = $this->get_lightbox_attributes($show_lightbox, $panel, $module);
66 - $link_attributes_text = $this->get_text_from_link_attributes($link_attributes);
72 + $gallery_figure_classes = ['photonic-level-1', 'photonic-thumb'];
67 73
68 - $effect = $this->get_thumbnail_effect($short_code, $layout, $title_position);
69 - $ul_class = "class='title-display-$title_position photonic-level-1-container ".($non_standard ? 'photonic-'.$layout.'-layout' : 'photonic-standard-layout')." photonic-thumbnail-effect-$effect'";
70 - if ($display == 'popup') {
71 - $ul_class = "class='slideshow-grid-panel lib-{$this->library} photonic-level-1-container title-display-$title_position'";
72 - }
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'] ?: [];
73 78
74 79 $ret = '';
75 - if (!$non_standard && $display != 'popup') {
76 - $container_tag = 'ul';
77 - $element_tag = 'li';
78 - }
79 - else {
80 - $container_tag = 'div';
81 - $element_tag = 'div';
82 - }
83 80
84 - list($pagination_data, $pagination, $columns_data) = $this->get_gallery_data_attributes($short_code, $module, $pagination, $columns);
85 -
86 - $start_with = "$indent<$container_tag $container_id $ul_class $pagination_data $columns_data>\n";
87 - $ret .= $start_with;
88 -
89 81 global $photonic_external_links_in_new_tab;
90 82 if (!empty($photonic_external_links_in_new_tab)) {
91 83 $target = " target='_blank' ";
84 + $anchor_lightbox_data['target'] = '_blank';
92 85 }
93 86 else {
94 87 $target = '';
95 88 }
@@ -94,162 +87,154 @@
94 87 $target = '';
95 88 }
96 89
97 90 $counter = 0;
98 - $thumbnail_class = " class='$layout' ";
99 91
100 - $element_start = "$indent\t<".$element_tag.' class="photonic-'.$module->provider.'-image photonic-'.$module->provider.'-'.$type.' '.$col_class.'">'."\n";
92 + $layout_engine = $this->get_layout_engine($module, $short_code);
93 + $all_sizes_present = strtolower($layout_engine) === 'css';
101 94
102 - $default_lightbox_text = apply_filters('photonic_default_lightbox_text', esc_attr__('View', 'photonic'));
103 - foreach ($photos as $photo) {
95 + $grid_figures = [];
96 +
97 + /** @var Photo $photo */
98 + foreach ($photos as $idx => $photo) {
104 99 $counter++;
105 100
106 - $thumb = ($non_standard && $display == 'in-page') ? (isset($photo['tile_image']) ? $photo['tile_image'] : $photo['main_image']) : $photo['thumbnail'];
107 - $orig = empty($photo['video']) ? $photo['main_image'] : $photo['video'];
108 -// $orig = $photo['main_image'];
109 - $url = isset($photo['main_page']) ? $photo['main_page'] : '';
110 - $title = esc_attr($photo['title']);
111 - $description = esc_attr($photo['description']);
112 - $alt = esc_attr($photo['alt_title']);
113 - $orig = ($this->library == 'none' || !$show_lightbox) ? $url : $orig;
114 -
115 - $title = empty($title) ? ((empty($alt) && $module->link_lightbox_title && $this->library != 'thickbox') ? $default_lightbox_text : $alt) : $title;
116 - $ret .= $element_start;
117 -
118 - $deep_value = 'gallery[photonic-'.$module->provider.'-'.$parent.'-'.(empty($panel) ? $module->gallery_index : $panel).']/'.(empty($photo['id']) ? $counter : $photo['id']).'/';
119 - $deep_link = ' data-photonic-deep="'.$deep_value.'" ';
120 -
121 - $buy = '';
122 - if (!empty($photo['buy_link']) && $module->show_buy_link) {
123 - $buy = ' data-photonic-buy="'.$photo['buy_link'].'" ';
101 + $figure_data = [];
102 + if ('masonry-horizontal' === $layout) {
103 + $figure_data['data-photonic-idx'] = $idx;
124 104 }
125 105
126 - $style = [];
127 - if (!empty($sizes['thumb-width'])) $style[] = 'width:'.$sizes['thumb-width'].'px';
128 - if (!empty($sizes['thumb-height'])) $style[] = 'height:'.$sizes['thumb-height'].'px';
129 - if (!empty($style)) $style = 'style="'.implode(';', $style).'"'; else $style = '';
130 - if ($module->link_lightbox_title && $this->library != 'thickbox' && !empty($url)) {
131 - $title_link_start = esc_attr("<a href='$url' $target>");
132 - $title_link_end = esc_attr("</a>");
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 + }
133 116 }
134 117 else {
135 - $title_link_start = '';
136 - $title_link_end = '';
118 + $thumb = $photo->thumbnail;
119 + if (!empty($photo->thumb_size)) {
120 + $inbuilt_sizes = $photo->thumb_size;
121 + }
137 122 }
138 123
139 - if (!empty($short_code['caption']) && ($short_code['caption'] == 'desc' || ($short_code['caption'] == 'title-desc' && empty($title)) || ($short_code['caption'] == 'desc-title' && !empty($description)))) {
140 - $title = $description;
124 + if (!empty($inbuilt_sizes)) {
125 + if ('random' === $layout) {
126 + $styles['--dw'] = $inbuilt_sizes['w'];
127 + $styles['--dh'] = $inbuilt_sizes['h'];
128 + }
141 129 }
142 - else if (empty($short_code['caption']) || (($short_code['caption'] == 'desc-title' && empty($title)) || $short_code['caption'] == 'none')) {
143 - $title = '';
130 + else {
131 + $all_sizes_present = false;
144 132 }
145 133
146 - if (!empty($title)) {
147 - $title_markup = $title_link_start.esc_attr($title).$title_link_end;
148 - $title_markup = apply_filters('photonic_lightbox_title_markup', $title_markup);
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);
149 139 }
150 - else {
151 - $title_markup = '';
152 - }
153 140
154 - if ($module->link_lightbox_title && $this->library != 'thickbox' && !empty($photo['buy_link']) && $module->show_buy_link) {
155 - $buy_link = esc_attr('<a class="photonic-buy-link" href="'.$photo['buy_link'].'" target="_blank" title="'.__('Buy', 'photonic').'"><div class="icon-buy"></div></a>');
156 - $title_markup .= $buy_link;
157 - }
141 + $title = wp_kses_post($photo->title);
142 + $description = wp_kses_post($photo->description);
143 + $alt = wp_kses_post($photo->alt_title);
158 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 +
159 156 $shown_title = '';
160 - if (in_array($title_position, ['below', 'hover-slideup-show', 'hover-slidedown-show', 'slideup-stick']) && !empty($title)) {
161 - $shown_title = '<div class="photonic-title-info"><div class="photonic-photo-title photonic-title">'.wp_specialchars_decode($title, ENT_QUOTES).'</div></div>';
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>';
162 161 }
163 162
164 - $photo_data = ['title' => $title_markup, 'deep' => $deep_value, 'raw_title' => $title, 'href' => $orig];
165 - if (!empty($photo['download'])) {
166 - $photo_data['download'] = $photo['download'];
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);
167 166 }
168 - if (!empty($photo['video'])) {
169 - $photo_data['video'] = $photo['video'];
167 + if (!empty($photo->video)) {
168 + $photo_data['video'] = esc_url($photo->video);
169 + $photo_data['poster'] = esc_url($photo->main_image);
170 170 }
171 171 else {
172 - $photo_data['image'] = $photo['main_image'];
172 + $photo_data['image'] = esc_url($photo->main_image);
173 173 }
174 - $photo_data['provider'] = $module->provider;
175 - $photo_data['gallery_index'] = $module->gallery_index;
176 - $photo_data['id'] = $photo['id'];
174 + $photo_data['id'] = $photo->id;
175 + $photo_data['thumbnail'] = $thumb;
177 176
178 - $lb_specific_data = $this->get_lightbox_specific_photo_data($photo_data, $module);
179 - if (!empty($photo['video'])) {
180 - $lb_specific_data .= ' data-photonic-media-type="video" ';
177 + if (!empty($photo->main_size)) {
178 + $photo_data['width'] = $photo->main_size['w'];
179 + $photo_data['height'] = $photo->main_size['h'];
181 180 }
182 - else {
183 - $lb_specific_data .= ' data-photonic-media-type="image" ';
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);
184 186 }
185 - if (!empty($photo['video']) && $this->library == 'lightgallery') {
186 - $video_id = $module->provider.'-'.$module->gallery_index.'-'.$photo['id'];
187 - $ret .= $indent."\t\t".'<div style="display:none;" id="photonic-video-'.$video_id.'">'."\n";
188 - $ret .= $indent."\t\t\t".'<video class="lg-video-object lg-html5 photonic" controls preload="none">'."\n";
189 - $ret .= $indent."\t\t\t\t".'<source src="'.$photo['video'].'" type="'.(!empty($photo['mime']) ? $photo['mime']: 'video/mp4').'">'."\n";
190 - $ret .= $indent."\t\t\t\t".esc_html__('Your browser does not support HTML5 videos.', 'photonic')."\n";
191 - $ret .= $indent."\t\t\t".'</video>'."\n";
192 - $ret .= $indent."\t\t".'</div>'."\n";
193 187
194 - $orig = ''; // href should be blank
195 - }
196 - else if (!empty($photo['video']) && (in_array($this->library, ['colorbox', 'fancybox', 'fancybox2', 'magnific', 'photoswipe', 'swipebox',])
197 - || (in_array($this->library, ['fancybox3']) && in_array($module->provider, ['flickr', 'google']))
198 - )) {
199 - $video_id = $module->provider.'-'.$module->gallery_index.'-'.$photo['id'];
200 - $ret .= $indent."\t\t".'<div class="photonic-html5-external" id="photonic-video-'.$video_id.'">'."\n";
201 - $ret .= $indent."\t\t\t".'<video class="photonic" controls preload="none">'."\n";
202 - $ret .= $indent."\t\t\t\t".'<source src="'.$photo['video'].'" type="'.(!empty($photo['mime']) ? $photo['mime']: 'video/mp4').'">'."\n";
203 - $ret .= $indent."\t\t\t\t".esc_html__('Your browser does not support HTML5 videos.', 'photonic')."\n";
204 - $ret .= $indent."\t\t\t".'</video>'."\n";
205 - $ret .= $indent."\t\t".'</div>'."\n";
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 ?? [];
206 193
207 - $orig = '#photonic-video-'.$video_id;
208 - }
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;
209 207
210 - if ($this->library == 'magnific') {
211 - $magnific = !empty($photo['video']) ? 'mfp-inline' : 'mfp-image';
212 - $link_attributes['class']['magnific'] = $magnific;
213 - $link_attributes_text = $this->get_text_from_link_attributes($link_attributes);
214 - }
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 215
216 - if ($title_position == 'tooltip') {
217 - $tooltip = 'data-photonic-tooltip="'.esc_attr($title).'" ';
218 - }
219 - else {
220 - $tooltip = '';
221 - }
222 - $ret .= $indent."\t\t".'<a '.$link_attributes_text.' href="'.$orig.'" title="'.($title_position != 'none' ? esc_attr($title) : '').'" data-title="'.$title_markup.'" '.$tooltip.' '.$lb_specific_data.' '.$target.$deep_link.$buy.">\n";
223 - $ret .= $indent."\t\t\t".'<img alt="'.$alt.'" src="'.$thumb.'" '.$style.$thumbnail_class." loading='eager'/>\n";
224 - $ret .= $indent."\t\t\t".$shown_title."\n";
225 - $ret .= $indent."\t\t"."</a>\n";
226 - $ret .= $indent."\t"."</$element_tag>\n";
216 + $grid_figures[] = $grid_figure;
227 217 }
228 218
229 - $ret = trim($ret);
230 - if ($ret != $start_with) {
231 - $trailing = strlen($element_tag) + 3;
232 - if (substr($ret, -$trailing) != "</$element_tag>" && $short_code['popup'] == 'show' && !$non_standard) {
233 - $ret .= "\n$indent</$element_tag><!-- last $element_tag.photonic-pad-photos -->";
234 - }
219 + if (!empty($grid_figures)) {
220 + $this->set_lazy_loading_attributes($all_sizes_present, $grid_figures);
235 221
236 - $ret .= "\n$indent</$container_tag> <!-- ./photonic-level-1-container -->\n";
237 - $ret .= "<span id='$container_end'></span>";
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();
238 224
239 - if (!empty($pagination) && isset($pagination['end']) && isset($pagination['total']) && $pagination['total'] > $pagination['end']) {
240 - $ret .= !empty($more) ? "<a href='#' class='photonic-more-button photonic-more-dynamic'>$more</a>\n" : '';
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);
241 234 }
242 - }
243 - else {
244 - $ret = '';
245 - }
246 235
247 - if (is_archive() || is_home()) {
248 - global $photonic_archive_thumbs;
249 - if (!empty($photonic_archive_thumbs) && $counter < $photonic_archive_thumbs) {
250 - $module->is_more_required = false;
251 - }
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);
252 237 }
253 238
254 239 $module->pop_from_stack();
255 240 return $ret;
@@ -259,173 +244,153 @@
259 244 * Generates the HTML for a group of level-2 items, i.e. Photosets (Albums) and Galleries for Flickr, Albums for Google Photos,
260 245 * Albums for SmugMug, and Photosets (Galleries and Collections) for Zenfolio. No concept of albums
261 246 * exists in native WP and Instagram.
262 247 *
263 - * @param $objects
264 - * @param $options
265 - * @param $short_code
266 - * @param $module Core
248 + * @param Album_List $album_list
249 + * @param array $short_code
250 + * @param Base $module
267 251 * @return string
268 252 */
269 - function generate_level_2_gallery($objects, $options, $short_code, $module) {
253 + public function generate_level_2_gallery(Album_List $album_list, array $short_code, Base $module): string {
270 254 $module->push_to_stack('Generate Level 2 Gallery');
271 - $row_constraints = isset($options['row_constraints']) && is_array($options['row_constraints']) ? $options['row_constraints'] : [];
272 - $type = $options['type'];
273 - $singular_type = $options['singular_type'];
274 - $title_position = empty($short_code['title_position']) ? $options['title_position'] : $short_code['title_position'];
275 - $level_1_count_display = $options['level_1_count_display'];
276 - $indent = !isset($options['indent']) ? '' : $options['indent'];
277 - $provider = $module->provider;
278 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');
279 261 $columns = $short_code['columns'];
280 - $layout = !isset($short_code['layout']) ? 'square' : $short_code['layout'];
281 - $popup = ' data-photonic-popup="'.$short_code['popup'].'"';
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;
282 267
283 - $non_standard = $layout == 'random' || $layout == 'masonry' || $layout == 'mosaic';
284 - $effect = $this->get_thumbnail_effect($short_code, $layout, $title_position);
285 - $ul_class = "class='title-display-$title_position photonic-level-2-container ".($non_standard ? 'photonic-'.$layout.'-layout' : 'photonic-standard-layout')." photonic-thumbnail-effect-$effect'";
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);
286 271
287 - list($container_id, $container_end) = $this->get_container_details($short_code, $module);
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 + );
288 280
289 - $pagination = isset($options['pagination']) && is_array($options['pagination']) ? $options['pagination'] : [];
290 - $more = !empty($short_code['more']) ? esc_attr($short_code['more']) : '';
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));
291 285
292 - list($pagination_data, $pagination, $columns_data) = $this->get_gallery_data_attributes($short_code, $module, $pagination, $columns);
286 + $gallery_figure_classes = ['photonic-level-2', 'photonic-thumb'];
293 287
294 - $ret = "\n$indent<ul $container_id $ul_class $pagination_data $columns_data>";
295 - if ($non_standard) {
296 - $ret = "\n$indent<div $container_id $ul_class $pagination_data $columns_data>";
288 + $gallery_anchor_classes = ['photonic-level-2-thumb'];
289 + if ($album_list->album_opens_gallery) {
290 + $gallery_anchor_classes[] = 'gallery-page';
297 291 }
298 292
299 - if ($columns != 'auto') {
300 - $col_class = 'photonic-gallery-'.$columns.'c';
301 - }
302 - else if ($row_constraints['constraint-type'] == 'padding') {
303 - $col_class = 'photonic-pad-'.$type;
304 - }
305 - else {
306 - $col_class = 'photonic-gallery-'.$row_constraints['count'].'c';
307 - }
293 + $layout_engine = $this->get_layout_engine($module, $short_code);
294 + $all_sizes_present = strtolower($layout_engine) === 'css';
308 295
309 - $col_class .= ' photonic-level-2 photonic-thumb';
296 + $ret = '';
297 + $grid_figures = [];
310 298
311 - $counter = 0;
312 - foreach ($objects as $object) {
313 - $data_attributes = isset($object['data_attributes']) && is_array($object['data_attributes']) ? $object['data_attributes'] : [];
314 - $data_attributes['provider'] = $provider;
315 - $data_attributes['singular'] = $singular_type;
299 + /** @var Album $object */
300 + foreach ($objects as $idx => $object) {
301 + $data_attributes = $object->data_attributes ?: [];
302 + $styles = [];
316 303
317 - $data_array = [];
304 + $figure_data = [];
305 + if ('masonry-horizontal' === $layout) {
306 + $figure_data['data-photonic-idx'] = $idx;
307 + }
308 +
309 + $anchor_data = [];
318 310 foreach ($data_attributes as $attr => $value) {
319 - $data_array[] = 'data-photonic-'.$attr.'="'.$value.'"';
311 + $anchor_data['data-photonic-' . $attr] = $value;
320 312 }
321 - $data_array = implode(' ', $data_array);
322 313
314 + $id = empty($object->id) ? '' : $object->id . '-';
315 + $id = esc_attr($id . $module->gallery_index);
316 + $title = wp_kses_post($object->title);
323 317
324 - $id = empty($object['id_1']) ? '' : $object['id_1'].'-';
325 - $id = $id.$module->gallery_index;
326 - $id = empty($object['id_2']) ? $id : ($id.'-'.$object['id_2']);
327 - $title = esc_attr($object['title']);
328 - $image = "<img src='".(($non_standard && isset($object['tile_image'])) ? $object['tile_image'] : $object['thumbnail'])."' alt='".$title."' class='$layout' loading='eager'/>";
329 - $additional_classes = !empty($object['classes']) ? implode(' ', $object['classes']) : '';
330 - $realm_class = '';
331 - if (!empty($object['classes'])) {
332 - foreach ($object['classes'] as $class) {
333 - if (stripos($class, 'photonic-'.$provider.'-realm') !== FALSE) {
334 - $realm_class = $class;
335 - }
336 - }
318 + $anchor_data['data-title'] = esc_attr($title);
319 +
320 + if ('tooltip' === $title_position) {
321 + $anchor_data['data-photonic-tooltip'] = esc_attr($title);
337 322 }
338 - if ($title_position == 'tooltip') {
339 - $tooltip = "data-photonic-tooltip='".esc_attr($title)."' ";
323 +
324 + if ($non_standard && !empty($object->tile_image)) {
325 + $img_src = $object->tile_image;
326 + $inbuilt_sizes = $object->tile_size ?: [];
340 327 }
341 328 else {
342 - $tooltip = '';
329 + $img_src = $object->thumbnail;
330 + $inbuilt_sizes = $object->thumb_size ?: [];
343 331 }
344 332
345 - if (empty($object['gallery_url'])) {
346 - $anchor = "\n{$indent}\t\t<a href='{$object['main_page']}' class='photonic-{$provider}-{$singular_type}-thumb photonic-level-2-thumb $additional_classes' id='photonic-{$provider}-$singular_type-thumb-$id' title='".($title_position != 'none' ? esc_attr($title) : '')."' data-title='".$title."' $tooltip $data_array$popup>\n$indent\t\t\t".$image;
333 + if (!empty($inbuilt_sizes)) {
334 + if ('random' === $layout) {
335 + $styles['--dw'] = $inbuilt_sizes['w'];
336 + $styles['--dh'] = $inbuilt_sizes['h'];
337 + }
347 338 }
348 339 else {
349 - $anchor = "\n{$indent}\t\t<a href='{$object['gallery_url']}' class='photonic-{$provider}-{$singular_type}-thumb photonic-level-2-thumb gallery-page $additional_classes' id='photonic-{$provider}-$singular_type-thumb-$id' title='".($title_position != 'none' ? esc_attr($title) : '')."' data-title='".$title."' $tooltip $data_array$popup>\n$indent\t\t\t".$image;
340 + $all_sizes_present = false;
350 341 }
351 - $text = '';
352 - if (in_array($title_position, ['below', 'hover-slideup-show', 'hover-slidedown-show', 'slideup-stick'])) {
353 - $text = "\n{$indent}\t\t\t<div class='photonic-title-info'>\n{$indent}\t\t\t\t<div class='photonic-$singular_type-title photonic-title'>".$title."";
354 - if (!$level_1_count_display && !empty($object['counter'])) {
355 - $text .= '<span class="photonic-title-photo-count photonic-'.$singular_type.'-photo-count">'.sprintf(esc_html__('%s photos', 'photonic'), $object['counter']).'</span>';
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>';
356 348 }
349 + $shown_title .= "</div>\n$indent\t\t\t</figcaption>";
357 350 }
358 - if ($text != '') {
359 - $text .= "</div>\n{$indent}\t\t\t</div>";
360 - }
361 351
362 - $anchor .= $text."\n{$indent}\t\t</a>";
363 - $password_prompt = '';
364 - if (!empty($object['passworded'])) {
365 - $prompt_title = esc_attr__('Protected Content', 'photonic');
366 - $prompt_submit = esc_attr__('Access', 'photonic');
367 - $password_type = " type='password' ";
368 - $prompt_type = 'password';
369 - $prompt_text = esc_attr__('This album is password-protected. Please provide a valid password.', 'photonic');
370 - if (in_array("photonic-$provider-passworded-authkey", $object['classes'])) {
371 - $prompt_text = esc_attr__('This album is protected. Please provide a valid authorization key.', 'photonic');
372 - }
373 - else if (in_array("photonic-$provider-passworded-link", $object['classes'])) {
374 - $prompt_text = esc_attr__('This album is protected. Please provide the short-link for it.', 'photonic');
375 - $password_type = '';
376 - $prompt_type = 'link';
377 - }
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 ?? [];
378 357
379 - $password_prompt = "
380 - <div class='photonic-password-prompter $realm_class' id='photonic-{$provider}-$singular_type-prompter-$id' title='$prompt_title' data-photonic-prompt='$prompt_type'>
381 - <div class='photonic-password-prompter-content'>
382 - <div class='photonic-prompt-head'>
383 - <h3>
384 - <span class='title'>$prompt_title</span>
385 - <button class='close'>&times;</button>
386 - </h3>
387 - </div>
388 - <div class='photonic-prompt-body'>
389 - <p>$prompt_text</p>
390 - <input $password_type name='photonic-{$provider}-password' />
391 - <button class='photonic-{$provider}-submit photonic-password-submit confirm'>$prompt_submit</button>
392 - </div>
393 - </div>
394 - </div>";
395 - }
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;
396 367
397 - if ($non_standard) {
398 - $ret .= "\n$indent\t<div class='photonic-{$provider}-image photonic-{$provider}-$singular_type-thumb $col_class' id='photonic-{$provider}-$singular_type-$id'>{$anchor}{$password_prompt}\n$indent\t</div>";
399 - }
400 - else {
401 - $ret .= "\n$indent\t<li class='photonic-{$provider}-image photonic-{$provider}-$singular_type-thumb $col_class' id='photonic-{$provider}-$singular_type-$id'>{$anchor}{$password_prompt}\n$indent\t</li>";
402 - }
403 - $counter++;
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;
404 378 }
405 379
406 - if ($ret != "\n$indent<ul $container_id $ul_class $pagination_data $columns_data>" && !$non_standard) {
407 - $ret .= "\n$indent</ul>\n";
408 - }
409 - else if ($non_standard) {
410 - $ret .= "\n$indent</div>\n";
411 - }
412 - else {
413 - $ret = '';
414 - }
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);
415 383
416 - if (!empty($ret)) {
417 - $ret .= "<span id='$container_end'></span>";
418 - if (!empty($pagination) && isset($pagination['end']) && isset($pagination['total']) && $pagination['total'] > $pagination['end']) {
419 - $ret .= !empty($more) ? "<a href='#' class='photonic-more-button photonic-more-dynamic'>$more</a>\n" : '';
420 - }
421 - }
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 + ];
422 391
423 - if (is_archive() || is_home()) {
424 - global $photonic_archive_thumbs;
425 - if (!empty($photonic_archive_thumbs) && $counter < $photonic_archive_thumbs) {
426 - $module->is_more_required = false;
427 - }
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);
428 393 }
429 394
430 395 $module->pop_from_stack();
431 396 return $ret;
@@ -431,240 +396,231 @@
431 396 return $ret;
432 397 }
433 398
434 399 /**
435 - * @param $short_code
436 - * @param $module
400 + * @param array $short_code
401 + * @param Base $module
437 402 * @return array
438 403 */
439 - private function get_container_details($short_code, $module) {
440 - if ($short_code['display'] != 'popup') {
441 - $container_id = "id='photonic-{$module->provider}-stream-{$module->gallery_index}-container'";
442 - $container_end = "photonic-{$module->provider}-stream-{$module->gallery_index}-container-end";
443 - } else {
444 - $container_id = "id='photonic-{$module->provider}-panel-" . $short_code['panel'] . "-container'";
445 - $container_end = "photonic-{$module->provider}-panel-{$short_code['panel']}-container-end";
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";
446 408 }
447 - return [$container_id, $container_end];
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];
448 414 }
449 415
450 416 /**
451 - * @param array $link_attributes
417 + * @param array $short_code
418 + * @param Pagination $pagination
452 419 * @return string
453 420 */
454 - private function get_text_from_link_attributes($link_attributes) {
455 - $class = '';
456 - $rel = '';
457 - $specific = '';
458 - if (!empty($link_attributes['class'])) {
459 - $class = " class='".implode(' ', array_values($link_attributes['class']))."' ";
460 - }
421 + private function get_updated_data_query(array $short_code, Pagination $pagination): string {
422 + $to_be_glued = '';
461 423
462 - if (!empty($link_attributes['rel'])) {
463 - $rel = " rel='".implode(' ', $link_attributes['rel'])."' ";
464 - }
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 + }
465 433
466 - if (!empty($link_attributes['specific'])) {
467 - foreach ($link_attributes['specific'] as $key => $val) {
468 - $specific .= $key.'="'.implode(' ', $val).'" ';
434 + if (!empty($pagination->next_token)) {
435 + $to_be_glued[] = 'next_token=' . $pagination->next_token;
469 436 }
437 +
438 + $to_be_glued = implode('&', $to_be_glued);
439 + $to_be_glued = esc_attr($to_be_glued);
470 440 }
471 - return $class.$rel.$specific;
441 + return $to_be_glued;
472 442 }
473 443
474 444 /**
475 - * Depending on the lightbox library, this function provides the CSS class and the rel tag for the thumbnail. This method borrows heavily from
476 - * Justin Tadlock's Cleaner Gallery Plugin.
445 + * Returns the thumbnail effect that should be used for a gallery. Not all effects can be used by all types of layouts.
477 446 *
478 - * @param $show_lightbox
479 - * @param $rel_id
480 - * @param $module
481 - * @return array
447 + * @param $short_code
448 + * @param $layout
449 + * @param $title_position
450 + * @return string
482 451 */
483 - private function get_lightbox_attributes($show_lightbox, $rel_id, $module) {
484 - global $photonic_slideshow_mode;
485 - $rel = '';
486 - $ret = [
487 - 'class' => [],
488 - 'rel' => [],
489 - 'specific' => [],
490 - ];
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 + }
491 464
492 - if ($this->library != 'none' && $show_lightbox) {
493 - $ret['class'] = ['photonic-launch-gallery', 'launch-gallery-'.$this->library, $this->library];
494 - $rel = 'lightbox-photonic-'.$module->provider.'-stream-'.(empty($rel_id) ? $module->gallery_index : $rel_id);
495 - $ret['rel'] = [$rel];
496 -
497 - switch ($this->library) {
498 - case 'fancybox2':
499 - $ret['class'] = ['photonic-launch-gallery', 'launch-gallery-fancybox', 'fancybox'];
500 - break;
501 -
502 - case 'fancybox3':
503 - $ret['class'] = ['photonic-launch-gallery', 'launch-gallery-fancybox', 'fancybox'];
504 - $ret['specific'] = [
505 - 'data-fancybox' => [$rel],
506 - ];
507 - break;
508 -
509 - case 'prettyphoto':
510 - $ret['rel'] = ["photonic-prettyPhoto[{$rel}]"];
511 - break;
512 -
513 - case 'featherlight':
514 - $ret['class'] = ['photonic-launch-gallery', 'launch-gallery-featherlight'];
515 - break;
516 -
517 - case 'lightcase':
518 - $ret['specific'] = [
519 - 'data-rel' => ['lightcase:lightbox-photonic-'.$module->provider.'-stream-'.(empty($rel_id) ? $module->gallery_index : $rel_id).((isset($photonic_slideshow_mode) && $photonic_slideshow_mode == 'on') ? ':slideshow' : '')],
520 - ];
521 - break;
522 -
523 - case 'strip':
524 - global $photonic_lightbox_no_loop;
525 - $ret['specific'] = [
526 - 'data-strip-group' => [$rel],
527 - ];
528 - if (!empty($photonic_lightbox_no_loop)) {
529 - $ret['specific']['data-strip-group-options'] = ["loop: false"];
530 - }
531 - break;
532 -
533 - default:
534 - $ret['class'] = ['photonic-launch-gallery', 'launch-gallery-'.$this->library, $this->library];
535 - $ret['rel'] = ['lightbox-photonic-'.$module->provider.'-stream-'.(empty($rel_id) ? $module->gallery_index : $rel_id)];
536 - break;
537 - }
465 + if ('circle' === $layout && 'opacity' !== $effect) { // "Zoom" doesn't work for circle
466 + $thumbnail_effect = 'none';
538 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 + }
539 476
540 - return $ret;
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};
541 488 }
542 489
543 490 /**
544 - * Some lightboxes require some additional attributes for individual photos. E.g. Lightgallery requires something to show the title etc.
545 - * This method returns such additional information. Not to be confused with <code>get_lightbox_attributes</code>, which
546 - * returns information for the gallery as a whole.
547 - *
548 - * @param $photo_data
491 + * @param Album $object
492 + * @param string $provider
493 + * @param string $singular_type
494 + * @param string $id
549 495 * @return string
550 496 */
551 - private function get_lightbox_specific_photo_data($photo_data, $module) {
552 - if ($this->library == 'lightgallery') {
553 - $download = !empty($photo_data['download']) ? 'data-download-url="'.$photo_data['download'].'" ' : '';
554 - $video = !empty($photo_data['video']) ? ' data-html="#photonic-video-'.$module->provider.'-'.$module->gallery_index.'-'.$photo_data['id'].'" ' : '';
555 - return ' data-sub-html="'.$photo_data['title'].'" '.$video.$download;
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>";
556 516 }
557 - else if ($this->library == 'strip') {
558 - return ' data-strip-caption="'.$photo_data['title'].'" data-strip-options="onShow: function(a) { photonicStripSetHash('."'{$photo_data['deep']}'".'); }, afterHide: function() { photonicStripUnsetHash(); } " ';
559 - }
560 - else if ($this->library == 'lightcase' && $module->provider == 'google') {
561 - if (empty($photo_data['video'])) {
562 - return " data-lc-options='{\"type\": \"image\"}' ";
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';
563 530 }
564 - else {
565 - return " data-lc-options='{\"type\": \"video\"}' ";
566 - }
567 531 }
568 - else if ($this->library == 'fancybox' && $module->provider == 'google') {
569 - if (empty($photo_data['video'])) {
570 - return " data-fancybox='{type: \"image\"}' ";
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';
571 537 }
572 538 }
573 - else if ($this->library == 'fancybox2' && $module->provider == 'google') {
574 - if (empty($photo_data['video'])) {
575 - return " data-fancybox-type='image' ";
576 - }
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';
577 551 }
578 - else if (in_array($this->library, ['colorbox', 'fancybox', 'fancybox2', 'photoswipe', 'swipebox',]) ||
579 - (in_array($this->library, ['fancybox3', 'lightcase']) && in_array($module->provider, ['flickr'])) ||
580 - (in_array($this->library, ['fancybox3',]) && in_array($module->provider, ['google']))) {
581 - return !empty($photo_data['video']) ? ' data-html5-href="'.$photo_data['video'].'" ': '';
552 + else {
553 + $classes[] = $non_standard ? 'photonic-' . $layout . '-layout' : 'photonic-standard-layout';
554 + $classes[] = 'photonic-thumbnail-effect-' . $thumbnail_effect;
582 555 }
583 - else if ($this->library == 'featherlight') {
584 - $mime = (!empty($photo['mime']) ? $photo['mime']: 'video/mp4');
585 - if ($module->provider == 'google' && empty($photo_data['video'])) {
586 - return " data-featherlight-type='image' ";
587 - }
588 - else if ($module->provider == 'google' && !empty($photo_data['video'])) {
589 - return " data-featherlight='<video class=\"photonic\" controls preload=\"none\"><source src=\"".$photo_data['video']."\" type=\"".$mime."\">".esc_html__('Your browser does not support HTML5 videos.', 'photonic')."</video>' data-featherlight-type='html'";
590 - }
591 556
592 - return !empty($photo_data['video']) ? " data-featherlight='<video class=\"photonic\" controls preload=\"none\"><source src=\"".$photo_data['video']."\" type=\"".$mime."\">".esc_html__('Your browser does not support HTML5 videos.', 'photonic')."</video>' data-featherlight-type='video'" : '';
593 - }
594 - return '';
557 + return $classes;
595 558 }
596 559
597 560 /**
598 - * @param $short_code
599 - * @param $module
600 - * @param $pagination
601 - * @param $columns
602 - * @return array
561 + * @param bool $non_standard
562 + * @param string $columns
563 + * @param array $row_constraints
564 + * @return string
603 565 */
604 - private function get_gallery_data_attributes($short_code, $module, $pagination, $columns) {
605 - $pagination_data = '';
606 - if (!empty($pagination)) {
607 - $pagination_data = [];
608 - // Should have total, start, end, per-page
609 - foreach ($pagination as $meta => $value) {
610 - $pagination_data[] = 'data-photonic-stream-' . $meta . '="' . $value . '"';
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';
611 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 + }
612 581
613 - $pagination_data = implode(' ', $pagination_data);
614 - if (empty($pagination['provider'])) {
615 - $pagination_data .= ' data-photonic-stream-provider="' . $module->provider . '"';
616 - }
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 + );
617 592 }
593 + return implode(' ', $data_pieces);
594 + }
618 595
619 - $to_be_glued = '';
620 - if (!empty($short_code)) {
621 - $to_be_glued = [];
622 - foreach ($short_code as $name => $value) {
623 - if (is_scalar($value)) {
624 - $to_be_glued[] = $name . '=' . $value;
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;
625 606 }
607 + $photonic_tile_min_height = esc_attr($photonic_tile_min_height);
608 + $style = "style='--tile-min-height: {$photonic_tile_min_height}px'";
626 609 }
627 - if (!empty($pagination['next-token'])) {
628 - $to_be_glued[] = 'next_token=' . $pagination['next-token'];
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);
629 615 }
630 - $to_be_glued = implode('&', $to_be_glued);
631 - $to_be_glued = esc_attr($to_be_glued);
632 - }
633 616
634 - $pagination_data .= ' data-photonic-stream-query="' . $to_be_glued . '"';
635 - $columns_data = ' data-photonic-gallery-columns="' . $columns . '"';
636 - return [$pagination_data, $pagination, $columns_data];
637 - }
617 + $ret .= "\n$indent</div> <!-- ./photonic-level-$level-container -->";
618 + $ret .= "\n$indent<span id='$end_id'></span>";
638 619
639 - /**
640 - * Returns the thumbnail effect that should be used for a gallery. Not all effects can be used by all types of layouts.
641 - *
642 - * @param $short_code
643 - * @param $layout
644 - * @param $title_position
645 - * @return string
646 - */
647 - private function get_thumbnail_effect($short_code, $layout, $title_position) {
648 - if (!empty($short_code['thumbnail_effect'])) {
649 - $effect = $short_code['thumbnail_effect'];
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 + }
650 623 }
651 - else {
652 - global $photonic_standard_thumbnail_effect, $photonic_justified_thumbnail_effect, $photonic_mosaic_thumbnail_effect, $photonic_masonry_thumbnail_effect;
653 - $effect = $layout == 'mosaic' ? $photonic_mosaic_thumbnail_effect :
654 - ($layout == 'masonry' ? $photonic_masonry_thumbnail_effect :
655 - ($layout == 'random' ? $photonic_justified_thumbnail_effect :
656 - $photonic_standard_thumbnail_effect));
657 - }
658 -
659 - if ($layout == 'circle' && $effect != 'opacity') { // "Zoom" doesn't work for circle
660 - $thumbnail_effect = 'none';
661 - }
662 - else if (($layout == 'square' || $layout == 'launch' || $layout == 'masonry') && $title_position == 'below') { // For these combinations, Zoom doesn't work
663 - $thumbnail_effect = 'none';
664 - }
665 - else {
666 - $thumbnail_effect = $effect;
667 - }
668 - return apply_filters('photonic_thumbnail_effect', $thumbnail_effect, $short_code, $layout, $title_position);
624 + return $ret;
669 625 }
670 -}
626 +}