PluginProbe
Meow Gallery / 4.2.2
Meow Gallery v4.2.2
5.5.5 5.5.4 5.5.3 5.5.2 5.5.1 5.5.0 5.4.9 5.4.8 5.4.7 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 All 157 releases
← All changes | classes/core.php +40 -1276 5.5.2 → 4.2.2 View file →
@@ -2,75 +2,27 @@
2 2
3 3 class Meow_MGL_Core {
4 4
5 5 private $gallery_process = false;
6 - private $gallery_layout = 'tiles';
7 6 private $is_gallery_used = true; // TODO: Would be nice to detect if the gallery is actually used on the current page.
8 - private $skeleton_handler;
9 - private $pro_module = false;
10 7
11 - private static $plugin_option_name = 'mgl_options';
12 - private $pro;
13 - private $option_name = 'mgl_options';
14 - private $infinite_layouts = [
15 - 'tiles',
16 - 'masonry',
17 - 'justified',
18 - 'square',
19 - 'cascade',
20 - // 'carousel', Added dynamically if the option is enabled
21 - ];
22 -
23 - private $rewrittenMwlData = [];
24 -
25 8 public function __construct() {
26 9 load_plugin_textdomain( MGL_DOMAIN, false, MGL_PATH . '/languages' );
27 10
28 - //TODO: Move Skeleton into PRO
29 - // Initialize skeleton handler
30 - require_once( MGL_PATH . '/classes/skeleton.php' );
31 - $this->skeleton_handler = new Meow_MGL_Skeleton();
32 -
33 11 // Initializes the classes needed
34 - MeowKit_MGL_Helpers::is_rest() && new Meow_MGL_Rest( $this );
12 + MeowCommon_Helpers::is_rest() && new Meow_MGL_Rest( $this );
13 + is_admin() && new Meow_MGL_Admin();
14 + class_exists( 'MeowPro_MGL_Core' ) && new MeowPro_MGL_Core();
35 15
36 16 // The gallery build process should only be enabled if the request is non-asynchronous
37 - if ( !MeowKit_MGL_Helpers::is_asynchronous_request() ) {
17 + if ( !MeowCommon_Helpers::is_asynchronous_request() ) {
38 18 add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 25, 3 );
39 19 if ( is_admin() || $this->is_gallery_used ) {
40 20 new Meow_MGL_Run( $this );
41 21 }
42 22 }
43 -
44 - // Load the Pro version *after* loading the Run class due to the JS file was gatherd into one file.
45 -
46 - $this->pro_module = class_exists( 'MeowPro_MGL_Core' );
47 - if ( $this->pro_module ) {
48 - $this->pro = new MeowPro_MGL_Core( $this );
49 - } else {
50 - add_shortcode( 'meow-collection', array( $this, 'collection' ) );
51 - }
52 -
53 - // Initialize the Admin if needed
54 - add_action( 'init', array( $this, 'init' ) );
55 23 }
56 24
57 - function init() {
58 - is_admin() && new Meow_MGL_Admin( $this );
59 -
60 - global $wpmgl;
61 - $wpmgl = $this;
62 -
63 - if ( $this->pro_module ) {
64 - global $wpmgl_pro;
65 - $wpmgl_pro = $this->pro;
66 - }
67 - }
68 -
69 - function collection() {
70 - return "<b>Meow Collection</b>: This is only available in the Pro version. Please <a href='https://meowapps.com/products/meow-gallery-pro/'>upgrade to Meow Gallery Pro</a> to use this feature.";
71 - }
72 -
73 25 public function can_access_settings() {
74 26 return apply_filters( 'mgl_allow_setup', current_user_can( 'manage_options' ) );
75 27 }
76 28
@@ -83,9 +35,8 @@
83 35 // Rewrite the sizes attributes of the src-set for each image
84 36 function wp_get_attachment_image_attributes( $attr, $attachment, $size ) {
85 37 if (!$this->gallery_process)
86 38 return $attr;
87 -
88 39 $sizes = null;
89 40 if ( $this->gallery_layout === 'tiles' )
90 41 $sizes = '50vw';
91 42 else if ( $this->gallery_layout === 'masonry' )
@@ -101,291 +52,59 @@
101 52 $attr['sizes'] = $sizes;
102 53 return $attr;
103 54 }
104 55
105 - function get_rewritten_mwl_data() {
106 - return $this->rewrittenMwlData;
107 - }
56 + function gallery( $atts, $isPreview = false ) {
57 + $atts = apply_filters( 'shortcode_atts_gallery', $atts, null, $atts );
108 58
109 - function gallery( $atts, $options = [] ) {
110 - $atts = apply_filters( 'shortcode_atts_gallery', $atts, null, $atts, 'gallery' );
111 -
112 - $isPreview = isset( $options['isPreview'] ) ? $options['isPreview'] : false;
113 - $isRest = isset( $options['isRest'] ) ? $options['isRest'] : false;
114 -
115 - // Sanitize the atts to avoid XSS
116 - $atts = array_map( function( $x ) {
117 - if ( is_array( $x ) ) {
118 - // In case it contains an array, we need to sanitize each element, and avoid a string conversion issue
119 - return array_map( function( $y ) { return is_null( $y ) ? $y : esc_attr( $y ); }, $x );
120 - } else {
121 - // We don't sanitize null value, as it would convert it to a empty string
122 - return is_null( $x ) ? $x : esc_attr( $x );
123 - }
124 - }, $atts );
125 -
126 - if ( isset( $atts['meow'] ) && $atts['meow'] === 'false' ) {
127 - return gallery_shortcode( $atts );
128 - }
129 -
130 - // If the attributes contain "collection" then use the collection shortcode instead
131 - if ( isset( $atts['collection'] ) && !empty( $atts['collection'] ) ) {
132 - return do_shortcode( '[meow-collection id="' . $atts['collection'] . '"]' );
133 - }
134 -
135 - $image_ids = array();
136 - $layout = '';
137 -
138 - // All potential attributes that can be used to get the images for the gallery
139 - $has_id = isset( $atts['id'] ) && !empty( $atts['id'] );
140 - $has_ids = isset( $atts['ids'] ) && !empty( $atts['ids'] );
141 - $has_include = isset( $atts['include'] ) && !empty( $atts['include'] );
142 - $has_tags = isset( $atts['tags'] ) && !empty( $atts['tags'] );
143 - $has_posts = isset( $atts['posts'] ) && !empty( $atts['posts'] );
144 - $has_latest_posts = isset( $atts['latest_posts'] ) && !empty( $atts['latest_posts'] );
145 -
146 - if ( $has_id && $has_ids ) {
147 - unset( $atts['ids'] );
148 - error_log( "⚠️ Meow Gallery: in gallery $atts[id] both 'id' and 'ids' attributes are used in the same shortcode. 'id' will be ignored." );
149 - }
150 -
151 59 // Get the IDs
152 - #region media_ids
153 - if ( $has_id && !$has_ids ) {
154 - $shortcode_id = $atts['id'];
155 -
156 - try {
157 - $shortcode = $this->get_gallery_by_id( $shortcode_id );
158 - }
159 - catch ( Exception $e ) {
160 - return "<p class='meow-error'><b>Meow Gallery:</b> This ID wasn't found in the Gallery Manager. (ID: $shortcode_id). " . $e->getMessage() . "</p>";
161 - }
162 -
163 - if ( !isset( $shortcode['medias'] ) || !isset( $shortcode['medias']['thumbnail_ids'])) {
164 - return "<p class='meow-error'><b>Meow Gallery:</b> Thumbnail IDs not found.</p>";
165 - }
166 -
167 - $image_ids = $shortcode['medias']['thumbnail_ids'];
168 - unset( $shortcode['medias'] );
169 -
170 - //* We merge $atts into $shortcode ( not $shortcode into $atts ) so we can override the gallery settings even when using the ID.
171 - // Override specifics: "default" layout from atts should be the layout from shortcode
172 - if( array_key_exists('layout', $atts) && $atts['layout'] == 'default' )
173 - {
174 - $atts['layout'] = $shortcode['layout'];
175 - }
176 -
177 - $atts = array_merge( $shortcode, $atts );
60 + $images = array();
61 + if ( isset( $atts['ids'] ) )
62 + $images = $atts['ids'];
63 + if ( isset( $atts['include'] ) ) {
64 + $images = is_array( $atts['include'] ) ? implode( ',', $atts['include'] ) : $atts['include'];
65 + $atts['include'] = $images;
178 66 }
179 -
180 - // Real Media Library folder path (e.g. rml="2025/France/Tours").
181 - // Re-evaluated here (not only from the top) so it also works when the value
182 - // comes from a saved gallery loaded via [gallery id="..."]. The logic lives
183 - // in Meow_MGL_RML::get_image_ids() to keep this method clean.
184 - $has_rml = isset( $atts['rml'] ) && !empty( $atts['rml'] );
185 - if ( $has_rml ) {
186 - $rml_ids = Meow_MGL_RML::get_image_ids( $atts['rml'] );
187 - if ( is_wp_error( $rml_ids ) ) {
188 - return "<p class='meow-error'><b>Meow Gallery:</b> " . esc_html( $rml_ids->get_error_message() ) . "</p>";
189 - }
190 - $image_ids = implode( ',', $rml_ids );
67 + if ( empty( $images ) ) {
68 + $attachments = get_attached_media( 'image' );
69 + $attachmentIds = array_map( function($x) { return $x->ID; }, $attachments );
70 + if ( !empty( $attachmentIds ) )
71 + $images = implode( ',', $attachmentIds );
72 + else
73 + return "<p class='meow-error'><b>Meow Gallery:</b> The gallery is empty.</p>";
191 74 }
192 75
193 - if ( $has_ids ) {
194 - $image_ids = $atts['ids'];
195 - }
196 -
197 - if ( $has_include ) {
198 - $image_ids = is_array( $atts['include'] ) ? implode( ',', $atts['include'] ) : $atts['include'];
199 - $atts['include'] = $image_ids;
200 - }
201 -
202 - // Tags support
203 - if ( $has_tags ) {
204 - $tags = is_array( $atts['tags'] ) ? $atts['tags'] : array_map( 'trim', explode( ',', $atts['tags'] ) );
205 -
206 - // Try multiple common taxonomies used for media tagging
207 - $taxonomies_to_try = [ 'post_tag', 'media_tag', 'attachment_tag', 'attachment_category' ];
208 - $taxonomies_to_try = apply_filters( 'mgl_tags_taxonomies', $taxonomies_to_try );
209 -
210 - $tagged_media_ids = [];
211 -
212 - foreach ( $taxonomies_to_try as $taxonomy ) {
213 - if ( !taxonomy_exists( $taxonomy ) ) {
214 - continue;
215 - }
216 -
217 - $args = [
218 - 'post_type' => 'attachment',
219 - 'post_status' => 'inherit',
220 - 'posts_per_page' => -1,
221 - 'fields' => 'ids',
222 - 'tax_query' => [
223 - [
224 - 'taxonomy' => $taxonomy,
225 - 'field' => 'slug',
226 - 'terms' => $tags,
227 - ]
228 - ]
229 - ];
230 -
231 - $query = new WP_Query( $args );
232 - if ( !empty( $query->posts ) ) {
233 - $tagged_media_ids = array_merge( $tagged_media_ids, $query->posts );
234 - }
235 - }
236 -
237 - $tagged_media_ids = array_unique( $tagged_media_ids );
238 -
239 - if ( !empty( $tagged_media_ids ) ) {
240 - if ( !empty( $image_ids ) ) {
241 - // Merge with existing IDs
242 - $existing_ids = is_array( $image_ids ) ? $image_ids : explode( ',', $image_ids );
243 - $image_ids = implode( ',', array_unique( array_merge( $existing_ids, $tagged_media_ids ) ) );
244 - } else {
245 - $image_ids = implode( ',', $tagged_media_ids );
246 - }
247 - }
248 - }
249 -
250 - if ( $has_latest_posts ) {
251 - $num_posts = intval( $atts['latest_posts'] );
252 -
253 - if ( $num_posts > 0 ) {
254 -
255 - $latest_posts = get_posts( [ 'numberposts' => $num_posts ] );
256 - $latest_posts_ids = array_map( function( $x ) { return $x->ID; }, $latest_posts );
257 -
258 - if ( $has_posts ) {
259 - error_log( "⚠️ Meow Gallery: in gallery $atts[id] both 'latest_posts' and 'posts' attributes are used in the same shortcode. 'latest_posts' will be merged with 'posts'.");
260 - $atts['posts'] = array_merge( $latest_posts_ids, explode(',', $atts['posts']) );
261 - }
262 - else {
263 - $atts['posts'] = implode( ',', $latest_posts_ids );
264 - }
265 - }
266 -
267 - }
268 -
269 - $posts_ids = [];
270 - if ( $has_posts ) {
271 -
272 - $posts_ids = is_array( $atts['posts'] ) ? $atts['posts'] : explode( ',', $atts['posts'] );
273 - $featured_images = [];
274 -
275 - foreach ($posts_ids as $key => $post_id) {
276 - $image_id = get_post_thumbnail_id($post_id);
277 - if ($image_id === false || $image_id == 0) {
278 - unset($posts_ids[$key]);
279 - } else {
280 - $featured_images[] = $image_id;
281 - }
282 - }
283 -
284 - if ( count( $posts_ids ) !== count( $featured_images ) ) {
285 - return "<p class='meow-error'><b>Meow Gallery:</b> The number of featured images and posts id should be the same.</p>";
286 - }
287 -
288 - $image_ids = implode(',', $featured_images);
289 - $posts_ids = array_values($posts_ids);
290 - }
291 -
292 -
293 - // Filter the IDs
294 - $ids = is_array( $image_ids ) ? $image_ids : explode( ',', $image_ids );
295 - $ids = apply_filters( 'mgl_ids', $ids, $atts );
296 - $image_ids = implode( ',', $ids );
297 -
298 - #endregion
299 -
300 - // Use attached images if still empty
301 - if ( empty( $image_ids ) ) {
302 - return "<p class='meow-error'><b>Meow Gallery:</b> The gallery is empty.</p>";
303 - }
304 -
305 76 if ( $isPreview ) {
306 - $check = explode( ',', $image_ids );
77 + $check = explode( ',', $images );
307 78 $check = array_slice( $check, 0, 40 );
308 - $image_ids = implode( ',', $check );
79 + $images = implode( ',', $check );
309 80 }
310 81
311 - // Limit images on archive/listing pages (not viewing the full single post)
312 - $should_truncate = $this->get_option( 'truncate_on_listing', true );
313 - $is_archive_context = !is_singular() && !is_admin() && !$isPreview && !$isRest && $should_truncate;
314 - $is_archive_context = apply_filters( 'mgl_is_archive_context', $is_archive_context, $atts );
315 - if ( $is_archive_context ) {
316 - $archive_limit = intval( $this->get_option( 'truncate_count', 4 ) );
317 -
318 - if( $archive_limit === 0 ) {
319 - return ""; // If the user does not want the gallery to be shown at all on listing pages
320 - }
321 -
322 - if ( $archive_limit > 0 ) {
323 - $check = explode( ',', $image_ids );
324 - if ( count( $check ) > $archive_limit ) {
325 - $check = array_slice( $check, 0, $archive_limit );
326 - $image_ids = implode( ',', $check );
327 - $atts['is_truncated'] = true; // Flag to potentially show "view more" indicator
328 - }
329 - }
330 - }
331 -
332 82 // Ordering
333 - if ( isset( $atts['orderby'] ) || isset( $atts['order_by'] ) ) {
334 -
335 - $orderby = '';
336 - $order = 'asc';
337 -
338 - if ( isset( $atts['order'] ) ) {
339 - $order = $atts['order'];
340 - }
341 -
342 - if ( isset( $atts['orderby'] ) ) {
343 - $orderby = $atts['orderby'];
344 - }
345 -
346 - if ( isset( $atts['order_by'] ) ) {
347 - $orderby = $atts['order_by'];
348 - }
349 -
350 - if( strpos( $orderby, '-' ) != false ) {
351 - $left = explode( '-', $orderby )[0];
352 - $right = explode( '-', $orderby )[1];
353 -
354 - $orderby = $left;
355 - $order = $right;
356 - }
357 -
358 -
359 - $image_ids = explode( ',', $image_ids );
360 - $image_ids = Meow_MGL_OrderBy::run( $image_ids, $orderby, $order );
361 - $image_ids = implode( ',', $image_ids );
83 + if ( isset( $atts['orderby'] ) ) {
84 + $images = explode( ',', $images );
85 + $images = Meow_MGL_OrderBy::run( $images, $atts['orderby'], isset( $atts['order'] ) ? $atts['order'] : 'asc' );
86 + $images = implode( ',', $images );
362 87 }
363 -
88 +
364 89 // Layout
365 - if ( isset( $atts['layout'] ) && $atts['layout'] != 'default' ) {
90 + $layout = 'none';
91 + if ( isset( $atts['layout'] ) && $atts['layout'] != 'default' )
366 92 $layout = $atts['layout'];
367 - }
368 - else if ( isset( $atts['mgl-layout'] ) && $atts['mgl-layout'] != 'default' ) {
93 + else if ( isset( $atts['mgl-layout'] ) && $atts['mgl-layout'] != 'default' )
369 94 $layout = $atts['mgl-layout'];
370 - $atts['layout'] = $layout;
371 - } else {
372 - $layout = $this->get_option( 'layout', 'tiles' );
373 - $atts['layout'] = $layout;
374 - }
95 + else
96 + $layout = get_option( 'mgl_layout', 'tiles' );
375 97
376 -
377 - if ( $layout === 'none' || $layout === '' ) {
378 - $layout = $this->get_option( 'layout', 'tiles' );
379 - }
380 -
381 -
98 + // Check the settings
99 + if ( $layout === 'none' )
100 + return gallery_shortcode( $atts );
382 101 $layoutClass = 'Meow_MGL_Builders_' . ucfirst( $layout );
383 102 if ( !class_exists( $layoutClass ) ) {
384 103 error_log( "Meow Gallery: Class $layoutClass does not exist." );
385 104 return "<p class='meow-error'><b>Meow Gallery:</b> The layout $layout is not available in this version.</p>";
386 105 }
387 -
106 +
388 107 // Captions
389 108 if ( isset( $atts['captions'] ) && ( $atts['captions'] === false || $atts['captions'] === 'false' ) ) {
390 109 // This is to avoid issues linked to the old block editor for the Meow Gallery
391 110 $atts['captions'] = 'none';
@@ -390,13 +109,8 @@
390 109 // This is to avoid issues linked to the old block editor for the Meow Gallery
391 110 $atts['captions'] = 'none';
392 111 }
393 112
394 - // apply filter 'mgl_sort_ahead' to sort the images before anything else
395 - if ( !empty( $image_ids ) ){
396 - $image_ids = implode( ',', apply_filters( 'mgl_sort_ahead', explode( ',', $image_ids ), $layout, $atts ) );
397 - }
398 -
399 113 //DEBUG: Display $atts
400 114 //error_log( print_r( $atts, 1 ) );
401 115
402 116 // Start the process of building the gallery
@@ -401,967 +115,17 @@
401 115
402 116 // Start the process of building the gallery
403 117 $this->gallery_process = true;
404 118 $this->gallery_layout = $layout;
405 -
406 - // This should be probably removed.
407 - // wp_enqueue_style( 'mgl-css' );
408 -
409 - $infinite = $this->get_option( 'infinite', false ) && class_exists( 'MeowPro_MGL_Core' );
410 -
411 - // $gen = new $layoutClass( $atts, !$isPreview && $infinite, $isPreview );
412 - // $result = $gen->build( $image_ids );
413 -
119 + wp_enqueue_style( 'mgl-css' );
120 + $infinite = get_option( 'mgl_infinite', false ) && class_exists( 'MeowPro_MGL_Core' );
121 + $gen = new $layoutClass( $atts, !$isPreview && $infinite, $isPreview );
122 + $result = $gen->build( $images );
123 + $this->gallery_process = false;
414 124 do_action( 'mgl_' . $layout . '_gallery_created', $layout );
415 125 //$result = apply_filters( 'post_gallery', $result, $atts, null );
416 -
417 - $this->rewrittenMwlData = apply_filters('mgl_force_rewrite_mwl_data', explode( ',', $image_ids ) );
418 - do_action( 'mgl_gallery_created', $atts, explode( ',', $image_ids ), $layout );
419 126
420 - $gallery_options = $this->get_gallery_options( $image_ids, $atts, $infinite, $isPreview, $layout );
421 -
422 - // If infinite scroll option was enabled, get the images up to 12 at first.
423 - $loading_image_ids = explode(',', $image_ids);
424 - $loading_image_ids = apply_filters( 'mgl_sort', $loading_image_ids, [], $layout, $atts );
425 -
426 - // Only add the carousel to the infinite layouts if the option is enabled
427 - if( $infinite && $this->get_option( 'carousel_infinite', false ) ) {
428 - $this->infinite_layouts[] = 'carousel';
429 - }
430 -
431 - if (!$isPreview && $infinite && in_array( $layout, $this->infinite_layouts ) ) {
432 - $loading_image_ids = array_slice( $loading_image_ids, 0, 12 );
433 - }
434 -
435 - $gallery_images = $this->get_gallery_images( $loading_image_ids, $atts, $layout, $gallery_options['size'], $posts_ids );
436 -
437 - // Get the class and data attributes
438 - $class = $this->get_mgl_root_class( $atts );
439 - $data_atts = $this->get_data_as_json( $atts );
440 - $data_gallery_options = $this->get_data_as_json( $gallery_options );
441 - $data_gallery_images = $this->get_data_as_json( $gallery_images );
442 -
443 - $html = sprintf(
444 - '<div class="%s" data-gallery-options="%s" data-gallery-images="%s" data-atts="%s">',
445 - esc_attr( $class ),
446 - $data_gallery_options,
447 - $data_gallery_images,
448 - $data_atts
449 - );
450 -
451 - // Run at /wp-includes/formatting.php on line 6037
452 - // WordPress returns early if the text is simple ASCII without emoji-like content,
453 - // so we only need to check preg_split if WordPress would actually run it.
454 - $needs_emoji_check = str_contains( $html, '&#x' ) ||
455 - !( ( function_exists( 'mb_check_encoding' ) && mb_check_encoding( $html, 'ASCII' ) ) || ! preg_match( '/[^\x00-\x7F]/', $html ) );
456 -
457 - if ( $needs_emoji_check ) {
458 - $textarr = preg_split( '/(<.*>)/U', $html , -1, PREG_SPLIT_DELIM_CAPTURE);
459 - if ( $textarr === false ) {
460 - $error = preg_last_error();
461 - error_log( "[MEOW GALLERY] Regex: " . preg_last_error_msg() . " (Code $error)" );
462 - return "<p class='meow-error'><b>Meow Gallery:</b> The gallery is too large for your Wordpress pcre.backtrack_limit, increase it in your server settings, or reduce your gallery size.";
463 - }
464 - }
465 -
466 - //The Gallery Container is where the images in the right layout will be rendered.
467 - $html .= '<div class="mgl-gallery-container"></div>';
468 -
469 - // Add skeleton loading placeholder to prevent layout shift
470 - $skeleton_loading = $this->get_option( 'skeleton_loading', true );
471 - if ( $skeleton_loading ) {
472 - $image_count = count( $gallery_images );
473 - $html .= $this->skeleton_handler->get_skeleton_html( $layout, $gallery_options, $image_count );
474 - }
475 -
476 - // Use the DOM to generate the images (so that lightboxes can hook into them, and for better SEO)
477 - // If there are no images, the JS will look for the img_html and build the gallery from there.
478 - // TODO: We should check why it's not working with the carousel (for map, it's normal).
479 - if ( $layout !== 'map' && $layout !== 'carousel' && $this->get_option( 'rendering_mode', 'dom' ) === 'dom' ) {
480 - $html .= '<div class="mgl-gallery-images">';
481 -
482 - foreach ( $gallery_images as $image ) {
483 - if ( !empty( $image['link_href'] ) ) {
484 - // If there is a link, we will get the alt from the image id so we have a proper aria-label
485 - $aria_label = __('Open image', MGL_DOMAIN);
486 - $aria_value = esc_attr( get_post_meta( $image['id'], '_wp_attachment_image_alt', true ) );
487 - $aria = !empty( $aria_value ) ? $aria_label . ': ' . $aria_value : $aria_label;
488 -
489 - $custom_link_classes = apply_filters( 'mgl_custom_link_classes', '', $image );
490 - $html .= '<a class="' . $custom_link_classes . '" href="' . $image['link_href'] . '" target="' . $image['link_target'] . '" rel="' . $image['link_rel'] .
491 - '" aria-label="' . $aria . '">';
492 - $html .= $image['img_html'];
493 - $html .= '</a>';
494 - }
495 - else {
496 - $html .= $image['img_html'];
497 - }
498 - }
499 - $html .= '</div>';
500 - }
501 -
502 - $html .= '</div>';
503 -
504 - $this->gallery_process = false;
505 -
506 - return $html;
507 - }
508 -
509 - public function get_gallery_options(string $image_ids, array $atts, bool $infinite, bool $is_preview, string $layout) {
510 - $image_ids = explode(',', $image_ids);
511 - $wp_upload_dir = wp_upload_dir();
512 - $options = $this->get_all_options();
513 - $id = uniqid();
514 - $size = isset( $atts['size'] ) ? $atts['size'] : 'large';
515 - $size = apply_filters( 'mgl_media_size', $size );
516 - $custom_class = isset( $atts['custom-class'] ) ? $atts['custom-class'] : null;
517 - $link = isset( $atts['link'] ) ? $atts['link'] : ( $options['link'] ?? null );
518 - $updir = trailingslashit( $wp_upload_dir['baseurl'] );
519 - $captions = isset( $atts['captions'] ) ? $atts['captions'] : ( $options['captions'] ?? 'none' );
520 - $animation = null;
521 - if ( isset( $atts['animation'] ) && $atts['animation'] != 'default' ) {
522 - $animation = $atts['animation'];
523 - } else {
524 - $animation = $options['animation'] ?? null;
525 - }
526 - $class_id = 'mgl-gallery-' . $id;
527 - $layouts = [];
528 -
529 - // Justified
530 - $justified_row_height = $options['justified_row_height'];
531 - $justified_gutter = $options['justified_gutter'];
532 - if ( $layout === 'justified' ) {
533 - $justified_row_height = $atts['row-height'] ?? $options['justified_row_height'];
534 - $justified_gutter = $atts['gutter'] ?? $options['justified_gutter'];
535 - }
536 - // Masonry
537 - $masonry_gutter = $options['masonry_gutter'];
538 - $masonry_columns = $options['masonry_columns'];
539 - if ( $layout === 'masonry' ) {
540 - $masonry_gutter = $atts['gutter'] ?? $options['masonry_gutter'];
541 - $masonry_columns = $atts['columns'] ?? $options['masonry_columns'];
542 - }
543 - // Square
544 - $square_gutter = $options['square_gutter'];
545 - $square_columns = $options['square_columns'];
546 - if ( $layout === 'square' ) {
547 - $square_gutter = $atts['gutter'] ?? $options['square_gutter'];
548 - $square_columns = $atts['columns'] ?? $options['square_columns'];
549 - }
550 - // Cascade
551 - $cascade_gutter = $options['cascade_gutter'];
552 - if ( $layout === 'cascade' ) {
553 - $layouts = [ 'o', 'i', 'ii' ];
554 - $cascade_gutter = $atts['gutter'] ?? $options['cascade_gutter'];
555 - }
556 - // Tiles
557 - $tiles_gutter = $options['tiles_gutter'];
558 - $tiles_gutter_tablet = $options['tiles_gutter_tablet'];
559 - $tiles_gutter_mobile = $options['tiles_gutter_mobile'];
560 - $tiles_density = $options['tiles_density'];
561 - $tiles_density_tablet = $options['tiles_density_tablet'];
562 - $tiles_density_mobile = $options['tiles_density_mobile'];
563 - if ( $layout === 'tiles' ) {
564 - $tiles_gutter = $atts['gutter'] ?? $options['tiles_gutter'];
565 - $tiles_gutter_tablet = $atts['gutter'] ?? $options['tiles_gutter_tablet'];
566 - $tiles_gutter_mobile = $atts['gutter'] ?? $options['tiles_gutter_mobile'];
567 - $tiles_density = $atts['density'] ?? $options['tiles_density'];
568 - $tiles_density_tablet = $atts['density'] ?? $options['tiles_density_tablet'];
569 - $tiles_density_mobile = $atts['density'] ?? $options['tiles_density_mobile'];
570 - }
571 - // Horizontal
572 - $horizontal_gutter = $options['horizontal_gutter'];
573 - $horizontal_image_height = $options['horizontal_image_height'];
574 - $horizontal_hide_scrollbar = $options['horizontal_hide_scrollbar'];
575 - if ( $layout === 'horizontal' ) {
576 - $horizontal_gutter = $atts['gutter'] ?? $options['horizontal_gutter'];
577 - $horizontal_image_height = $atts['image_height'] ?? $options['horizontal_image_height'];
578 - $horizontal_hide_scrollbar = $atts['hide_scrollbar'] ?? $options['horizontal_hide_scrollbar'];
579 - }
580 - // Carousel
581 - $carousel_gutter = $options['carousel_gutter'];
582 - $carousel_arrow_nav_enabled = $options['carousel_arrow_nav_enabled'];
583 - $carousel_dot_nav_enabled = $options['carousel_dot_nav_enabled'];
584 - $carousel_image_height = $options['carousel_image_height'];
585 - $carousel_keep_aspect_ratio = $options['carousel_aspect_ratio'] ?? false;
586 - if ( $layout === 'carousel' ) {
587 - $carousel_gutter = $atts['gutter'] ?? $options['carousel_gutter'];
588 - $carousel_arrow_nav_enabled = $atts['arrow_nav_enabled'] ?? $options['carousel_arrow_nav_enabled'];
589 - $carousel_dot_nav_enabled = $atts['dot_nav_enabled'] ?? $options['carousel_dot_nav_enabled'];
590 - $carousel_image_height = $atts['image_height'] ?? $options['carousel_image_height'];
591 - $carousel_keep_aspect_ratio = array_key_exists( 'keep-aspect-ratio', $atts ) ? $atts['keep-aspect-ratio'] : 1;
592 - }
593 - // Map
594 - $map_gutter = $options['map_gutter'];
595 - $map_height = $options['map_height'];
596 - if ( $layout === 'map' ) {
597 - $map_gutter = $atts['gutter'] ?? $options['map_gutter'];
598 - $map_height = $atts['map_height'] ?? $options['map_height'];
599 - }
600 -
601 - return compact(
602 - 'image_ids',
603 - 'id',
604 - 'size',
605 - 'infinite',
606 - 'custom_class',
607 - 'link',
608 - 'is_preview',
609 - 'updir',
610 - 'captions',
611 - 'animation',
612 - 'layout',
613 - 'justified_row_height',
614 - 'justified_gutter',
615 - 'masonry_gutter',
616 - 'masonry_columns',
617 - 'square_gutter',
618 - 'square_columns',
619 - 'cascade_gutter',
620 - 'class_id',
621 - 'layouts',
622 - 'tiles_gutter',
623 - 'tiles_gutter_tablet',
624 - 'tiles_gutter_mobile',
625 - 'tiles_density',
626 - 'tiles_density_tablet',
627 - 'tiles_density_mobile',
628 - 'horizontal_gutter',
629 - 'horizontal_image_height',
630 - 'horizontal_hide_scrollbar',
631 - 'carousel_gutter',
632 - 'carousel_arrow_nav_enabled',
633 - 'carousel_dot_nav_enabled',
634 - 'carousel_image_height',
635 - 'carousel_keep_aspect_ratio',
636 - 'map_gutter',
637 - 'map_height',
638 - );
639 - }
640 -
641 - // #region Options
642 -
643 - static function get_plugin_option_name() {
644 - return self::$plugin_option_name;
645 - }
646 -
647 - static function get_plugin_option( $option_name, $default = null ) {
648 - $options = get_option( self::$plugin_option_name, null );
649 - if ( !empty( $options ) && array_key_exists( $option_name, $options ) ) {
650 - return $options[$option_name];
651 - }
652 - return $default;
653 - }
654 -
655 - function get_option( $option_name, $default = null ) {
656 - $options = $this->get_all_options();
657 - if ( array_key_exists( $option_name, $options ) ) {
658 - return $options[$option_name];
659 - }
660 - return $default;
661 - }
662 -
663 - function reset_options() {
664 - delete_option( 'mgl_db_version');
665 - delete_option( $this->option_name );
666 - }
667 -
668 - function list_options() {
669 - return array(
670 - 'layout' => 'tiles',
671 - 'ç' => 'none',
672 - 'link' => null,
673 - 'caption_source' => 'caption',
674 - 'captions_alignment' => 'center',
675 - 'captions_background' => 'fade-black',
676 - 'animation' => false,
677 - 'image_size' => 'srcset',
678 - 'truncate_on_listing' => true,
679 - 'truncate_count' => 4,
680 -
681 - 'rendering_mode' => 'dom', // Can be 'dom' or 'js'
682 - 'tiles_gutter' => 10,
683 - 'tiles_gutter_tablet' => 10,
684 - 'tiles_gutter_mobile' => 10,
685 - 'tiles_density' => 'high',
686 - 'tiles_density_tablet' => 'medium',
687 - 'tiles_density_mobile' => 'low',
688 -
689 - 'justified_density' => 'low',
690 - 'justified_density_tablet' => 'medium',
691 - 'justified_density_mobile' => 'low',
692 -
693 - 'masonry_gutter' => 5,
694 - 'masonry_columns' => 3,
695 - 'masonry_left_to_right' => false,
696 - 'justified_gutter' => 5,
697 - 'justified_row_height' => 200,
698 - 'square_gutter' => 5,
699 - 'square_columns' => 5,
700 - 'cascade_gutter' => 10,
701 - 'horizontal_gutter' => 10,
702 - 'horizontal_image_height' => 500,
703 - 'horizontal_hide_scrollbar' => false,
704 - 'carousel_gutter' => 5,
705 - 'carousel_image_height' => 500,
706 - 'carousel_arrow_nav_enabled' => true,
707 - 'carousel_dot_nav_enabled' => true,
708 - 'carousel_infinite' => false,
709 - 'map_engine' => 'googlemaps',
710 - 'map_height' => 500,
711 - 'map_zoom' => 10,
712 - 'map_gutter' => 10,
713 - 'googlemaps_token' => '',
714 - 'googlemaps_style' => '[]',
715 - 'mapbox_token' => '',
716 - 'mapbox_style' => '{"username":"", "style_id":""}',
717 - 'maptiler_token' => '',
718 -
719 - // Stylish effect options
720 - 'stylish_enabled' => false,
721 - 'stylish_border_radius' => 6,
722 - 'stylish_shadow_opacity' => 0.08,
723 - 'stylish_shadow_opacity_hover' => 0.12,
724 - 'stylish_transition_speed' => 250,
725 -
726 - //PRO OPTIONS
727 - 'infinite' => false,
728 - 'infinite_buffer' => 0,
729 - 'right_click' => false,
730 - 'gallery_shortcode_override_disabled' => false,
731 - 'skeleton_loading' => false,
732 - );
733 - }
734 -
735 - function list_pro_options() {
736 - return array(
737 - 'infinite' => false,
738 - 'infinite_buffer' => 0,
739 - 'right_click' => false,
740 - 'gallery_shortcode_override_disabled' => false,
741 - 'skeleton_loading' => false,
742 - );
743 - }
744 -
745 - function get_all_options() {
746 - $options = get_option( $this->option_name, null );
747 - $options = $this->check_options( $options );
748 - return $options;
749 - }
750 -
751 - // Upgrade from the old way of storing options to the new way.
752 -
753 - function check_options( $options = [] ) {
754 - $plugin_options = $this->list_options();
755 - $pro_options = $this->list_pro_options();
756 -
757 - $options = empty( $options ) ? [] : $options;
758 - $hasChanges = false;
759 -
760 - foreach ( $plugin_options as $option => $default ) {
761 - // The option already exists
762 - if ( isset( $options[$option] ) ) {
763 - continue;
764 - }
765 - // The option does not exist, so we need to add it.
766 - // Let's use the old value if any, or the default value.
767 - $options[$option] = get_option( 'mgl_' . $option, $default );
768 - delete_option( 'mgl_' . $option );
769 - $hasChanges = true;
770 - }
771 -
772 - if( !$this->pro_module ) {
773 - foreach ( $pro_options as $pro_option => $default ) {
774 - if ( $options[$pro_option] !== $default ) {
775 - $options[$pro_option] = $default;
776 - $hasChanges = true;
777 - }
778 - }
779 - }
780 -
781 - if ( $hasChanges ) {
782 - update_option( $this->option_name , $options );
783 - }
784 - return $options;
785 - }
786 -
787 - function update_options( $options ) {
788 - if ( !update_option( $this->option_name, $options, false ) ) {
789 - return false;
790 - }
791 - $options = $this->sanitize_options();
792 - return $options;
793 - }
794 -
795 -
796 - // Validate and keep the options clean and logical.
797 - function sanitize_options() {
798 - $options = $this->get_all_options();
799 - // something to do
800 - return $options;
801 - }
802 -
803 - # endregion
804 -
805 - function get_caption_from_source( $image ) {
806 - $caption_source = $this->get_option( 'caption_source', 'caption' );
807 - $caption = '';
808 -
809 - switch ( $caption_source ) {
810 - case 'title':
811 - $caption = $image->title;
812 - break;
813 - case 'caption':
814 - $caption = $image->caption;
815 - break;
816 - case 'description':
817 - $caption = $image->description;
818 - break;
819 - case 'alt':
820 - $caption = $image->alt;
821 - break;
822 - default:
823 - $caption = $image->caption;
824 - break;
825 - }
826 -
827 - return $caption;
828 - }
829 -
830 - function get_gallery_images( array $image_ids, array $atts, string $layout, string $size, array $posts_ids = []) {
831 - global $wpdb;
832 -
833 - // Escape the array of IDs for SQL
834 - $ids = array_map( 'intval', $image_ids );
835 - $ids_str = implode( ',', $ids );
836 -
837 - $query = "SELECT
838 - p.ID id,
839 - p.post_title title,
840 - p.post_content description,
841 - p.post_excerpt caption,
842 - pm.meta_value alt,
843 - pm2.meta_value meta
844 -
845 - FROM $wpdb->posts p
846 - LEFT JOIN $wpdb->postmeta pm ON pm.post_id = p.ID AND pm.meta_key = '_wp_attachment_image_alt'
847 - LEFT JOIN $wpdb->postmeta pm2 ON pm2.post_id = p.ID AND pm2.meta_key = '_wp_attachment_metadata'
848 -
849 - WHERE p.post_type = 'attachment'
850 -
851 - AND p.ID IN (" . $ids_str . ")
852 - ";
853 -
854 - $res = $wpdb->get_results( $query );
855 -
856 - $ids = explode( ',', $ids_str );
857 - $images = [];
858 - foreach ( $res as $r ) {
859 - $images[$r->id] = [
860 - 'caption' => $this->get_caption_from_source( $r ),
861 - 'meta' => unserialize( $r->meta ),
862 - ];
863 - }
864 - $cleanIds = [];
865 - foreach ( $ids as $id ) {
866 - if ( isset( $images[$id] ) )
867 - array_push( $cleanIds, $id );
868 - }
869 - $ids = apply_filters( 'mgl_sort', $cleanIds, $images, $layout, $atts );
870 -
871 - if ($layout === 'map') {
872 - return $this->get_map_images( $ids, $images, $atts );
873 - }
874 -
875 - $result = [];
876 - foreach ($ids as $index => $id) {
877 - $image = $images[$id];
878 -
879 - // Determine orientation if layout is 'tiles'
880 - $orientation = [];
881 - if ($layout === 'tiles') {
882 - $orientation = [
883 - 'orientation' => ($image['meta']['width'] > $image['meta']['height'] ? 'o' : 'i')
884 - ];
885 - }
886 -
887 - $default_link = $this->get_option( 'link', null );
888 - $link_attr = $this->get_link_attributes( $id, $atts['link'] ?? $default_link, $image );
889 - $no_lightbox = $link_attr['type'] === 'link';
890 -
891 - $mergedArray = [
892 - 'id' => $id,
893 - 'caption' => wp_kses(
894 - html_entity_decode(apply_filters( 'mgl_caption', $image['caption'], $id ), ENT_QUOTES),
895 - [
896 - 'strong' => [], // Bold
897 - 'b' => [], // Bold alternative
898 - 'em' => [], // Italic
899 - 'i' => [] // Italic alternative
900 - ]
901 - ),
902 - 'img_html' => apply_filters( 'mgl_gallery_written',
903 - $this->get_img_html( $id, $size, $layout, $atts, $image, $no_lightbox ),
904 - $layout
905 - ),
906 - 'link_href' => $link_attr['href'] ?? null,
907 - 'link_target' => $link_attr['target'] ?? null,
908 - 'link_rel' => $link_attr['rel'] ?? null,
909 - 'attributes' => $this->get_attributes( $id, $image, $layout ),
910 - ];
911 -
912 - if( !empty( $posts_ids ) && isset( $atts['hero'] ) && $atts['hero'] ) {
913 -
914 - $post_id = $posts_ids[$index];
915 - $post = get_post( $post_id );
916 -
917 - $mergedArray['featured_post_id'] = $post_id;
918 - $mergedArray['featured_post_title'] = $post->post_title;
919 - $mergedArray['featured_post_excerpt'] = $post->post_excerpt;
920 - $mergedArray['featured_post_url'] = get_permalink( $post_id );
921 -
922 - }
923 -
924 - $result[] = array_merge( $image, $mergedArray, $orientation );
925 - }
926 -
927 127 return $result;
928 128 }
929 -
930 - private function get_image_class( $id, $layout, $noLightbox ) {
931 - $base_class = 'wp-image-' . $id;
932 -
933 - if( $layout === 'carousel' ) {
934 - $base_class .= ' skip-lazy';
935 - }
936 -
937 - if ( $noLightbox ) {
938 - $base_class .= ' no-lightbox';
939 - }
940 - return $base_class;
941 - }
942 -
943 - private function get_img_html( $id, $size, $layout, $atts, $data, $noLightbox ) {
944 -
945 - //check if the media is a video
946 - $media_type = get_post_mime_type( $id );
947 - if ( strpos( $media_type, 'video' ) !== false ) {
948 - $video = wp_get_attachment_url( $id );
949 - $video = apply_filters( 'mgl_video', $video, $id, $data );
950 - if ( !empty( $video ) ) {
951 - return '<video class="wp-video-'. $id .'" controls="controls" onclick="() => this.play();"><source src="' . $video . '" type="' . $media_type . '"></video>';
952 - }
953 - }
954 -
955 - $image_size = $this->get_option( 'image_size', 'srcset' );
956 - $img_html = null;
957 - if ( empty( $image_size ) || $image_size === 'srcset' ) {
958 - $img_html = wp_get_attachment_image( $id, $size, false, [
959 - 'class' => $this->get_image_class( $id, $layout, $noLightbox ),
960 - 'draggable' => $layout === 'carousel' ? 'false' : null,
961 - ]);
962 - }
963 - else {
964 - $info = wp_get_attachment_image_src( $id, $image_size );
965 - $alt_text = get_post_meta( $id, '_wp_attachment_image_alt', true );
966 -
967 - $img_html = '<img loading="lazy" src="' . $info[0] . '" class="' . $this->get_image_class( $id, $layout, $noLightbox ) . '" alt="' . esc_attr( $alt_text ) . '" />';
968 - }
969 -
970 - if ( $layout === 'masonry' ) {
971 - $masonry_column = $this->get_option( 'masonry_column', 3 );
972 - $columns = ( isset( $atts['columns'] ) ? $atts['columns'] : $masonry_column ) + 1;
973 - $img_html = str_replace( '100vw', 100 / $columns . 'vw', $img_html );
974 - }
975 - else if ( $layout === 'square' ) {
976 - $square_column = $this->get_option( 'square_columns', 5 );
977 - $columns = ( isset( $atts['columns'] ) ? $atts['columns'] : $square_column ) + 1;
978 - $img_html = str_replace( '100vw', 100 / $columns . 'vw', $img_html );
979 - }
980 - else if ( $layout === 'cascade' ) {
981 - $img_html = str_replace( '100vw', 100 / 3 . 'vw', $img_html );
982 - }
983 -
984 - return wp_kses( $img_html, [
985 - 'img' => [
986 - 'src' => true,
987 - 'srcset' => true,
988 - 'loading' => true,
989 - 'tabindex' => true,
990 - 'sizes' => true,
991 - 'class' => true,
992 - 'id' => true,
993 - 'width' => true,
994 - 'height' => true,
995 - 'alt' => true,
996 - 'align' => true,
997 - 'draggable' => true,
998 - ]
999 - ]
1000 - );
1001 - }
1002 -
1003 - private function get_link_attributes( $id, $link, $data ) {
1004 - $link_url = null;
1005 - $type = 'media';
1006 - $rel = null;
1007 - $target = '_self';
1008 -
1009 - if ( $link === 'attachment' ) {
1010 - $link_url = get_permalink( (int)$id );
1011 - }
1012 - else if ( $link === 'media' || $link === 'file' ) {
1013 - $wpUploadDir = wp_upload_dir();
1014 - $updir = trailingslashit( $wpUploadDir['baseurl'] );
1015 - if ( isset( $data['meta']['file'] ) ) {
1016 - $link_url = $updir . $data['meta']['file'];
1017 - } else {
1018 - $link_url = get_permalink( (int)$id );
1019 - }
1020 - }
1021 - else if ( $link === null ){
1022 - $link_url = get_post_meta( $id, '_gallery_link_url', true );
1023 - if ( !empty( $link_url ) ) {
1024 - $type = 'link';
1025 - $target = get_post_meta( $id, '_gallery_link_target', true );
1026 - }
1027 - }
1028 -
1029 - $link_attr = [
1030 - 'href' => !empty( $link_url ) ? esc_url( $link_url ) : null,
1031 - 'target' => $target,
1032 - 'type' => $type,
1033 - 'rel' => $rel,
1034 - ];
1035 -
1036 -
1037 - return apply_filters( 'mgl_link_attributes', $link_attr, (int)$id, $data );
1038 - }
1039 -
1040 - private function get_attributes( $id, $data, $layout ) {
1041 - $attributes = '';
1042 - if ( $layout === 'raw' ) {
1043 - if ( isset( $data['meta'] ) && isset( $data['meta']['width'] ) && isset( $data['meta']['height'] ) ) {
1044 - $attributes = 'data-mgl-id=' . $id . ' data-mgl-width=' . $data['meta']['width'] . ' data-mgl-height=' . $data['meta']['height'];
1045 - }
1046 - }
1047 - elseif ( $layout === 'tiles' ) {
1048 - if ( isset( $data['meta'] ) && isset( $data['meta']['width'] ) && isset( $data['meta']['height'] ) ) {
1049 - $attributes = 'data-mgl-id=' . $id . ' data-mgl-width=' . $data['meta']['width'] . ' data-mgl-height=' . $data['meta']['height'];
1050 - }
1051 - }
1052 - $attributes = apply_filters( 'mgl_attributes', $attributes, $id, $data );
1053 - if ( $attributes === '' ) {
1054 - return [];
1055 - }
1056 -
1057 - $attribute_list = explode( ' ', $attributes );
1058 - $attributes = [];
1059 - foreach ( $attribute_list as $attribute ) {
1060 - list( $key, $value ) = explode( '=', $attribute );
1061 - $attributes[$key] = $value;
1062 - }
1063 - return $attributes;
1064 - }
1065 -
1066 - private function get_map_images( $ids, $images, $atts = [] ) {
1067 - $map_images = array_map( function ( $id ) use ( $images, $atts ) {
1068 -
1069 - $image = $images[$id];
1070 - $default_link = $this->get_option( 'link', null );
1071 - $link_attr = $this->get_link_attributes( $id, $atts['link'] ?? $default_link, $image );
1072 -
1073 - $geo_coordinates = MeowPro_MGL_Exif::get_gps_data( $id, $image['meta'] );
1074 - if ( empty( $geo_coordinates ) ) {
1075 - return null;
1076 - }
1077 - $callback = function ( &$value, $key ) use ( $id ) {
1078 - $imgsrc = wp_get_attachment_image_src( $id, $key );
1079 - $value = $imgsrc[0];
1080 - };
1081 - array_walk( $image['meta']['sizes'], $callback );
1082 - return array_merge(
1083 - $image,
1084 - [
1085 - 'id' => $id,
1086 - 'file' => $image['meta']['file'],
1087 - 'file_full' => wp_get_attachment_url( $id ),
1088 - 'file_srcset' => wp_get_attachment_image_srcset( $id, 'full' ),
1089 - 'file_sizes' => wp_get_attachment_image_sizes( $id, 'full' ),
1090 - 'dimension' => [
1091 - 'width' => $image['meta']['width'],
1092 - 'height' => $image['meta']['height'],
1093 - ],
1094 - 'sizes' => $image['meta']['sizes'],
1095 - 'data' => [
1096 - 'caption' => $image['meta']['image_meta']['caption'],
1097 - 'gps' => $geo_coordinates,
1098 - ],
1099 - 'link' => $link_attr,
1100 - ]
1101 - );
1102 - }, $ids );
1103 - return array_values( array_filter( $map_images ) );
1104 - }
1105 -
1106 - public function get_mgl_root_class( $atts, $classes = ['mgl-root'] ) {
1107 - $classes[] = isset( $atts['align'] ) ? 'align' . $atts['align'] : '';
1108 - return trim( implode( ' ', $classes ) );
1109 - }
1110 -
1111 - public function get_data_as_json( $data ) {
1112 - return esc_attr( htmlspecialchars( wp_json_encode( $data ), ENT_QUOTES, 'UTF-8' ) );
1113 - }
1114 -
1115 - public function generate_uniqid($length = 13) {
1116 - // Use WordPress function
1117 - if ( function_exists( 'wp_unique_id' ) ) {
1118 - $prefix = uniqid();
1119 - return wp_unique_id( $prefix );
1120 - }
1121 - // Fall back
1122 - else {
1123 - if ( function_exists( "random_bytes" ) ) {
1124 - $bytes = random_bytes( ceil( $length / 2 ) );
1125 - }
1126 - elseif ( function_exists( "openssl_random_pseudo_bytes" ) ) {
1127 - $bytes = openssl_random_pseudo_bytes(ceil($length / 2));
1128 - }
1129 - else {
1130 - throw new Exception( "No cryptographically secure random function available." );
1131 - }
1132 - return substr( bin2hex( $bytes ), 0, $length );
1133 - }
1134 - }
1135 -
1136 -
1137 - public function get_gallery_by_id( $id ) {
1138 - global $wpdb;
1139 - $shortcodes_table = $wpdb->prefix . 'mgl_gallery_shortcodes';
1140 - $gallery = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $shortcodes_table WHERE id = %s", $id ), ARRAY_A );
1141 -
1142 - if ( !$gallery ) {
1143 - throw new Exception( __( 'Gallery not found.', MGL_DOMAIN ));
1144 - }
1145 - $gallery['medias'] = maybe_unserialize( $gallery['medias'] );
1146 - $gallery['posts'] = $gallery['posts'] ? maybe_unserialize( $gallery['posts'] ) : null;
1147 - $gallery['tags'] = $gallery['tags'] ? unserialize( $gallery['tags'] ) : null;
1148 -
1149 - return $gallery;
1150 - }
1151 -
1152 - public function get_galleries_by_ids( $ids ){
1153 - global $wpdb;
1154 - $shortcodes_table = $wpdb->prefix . 'mgl_gallery_shortcodes';
1155 - $galleries = [];
1156 - $ids_str = "'" . implode( "','", array_map( 'esc_sql', $ids )) . "'";
1157 - $query = "SELECT * FROM $shortcodes_table WHERE id IN ( $ids_str )";
1158 - $results = $wpdb->get_results( $query, ARRAY_A );
1159 - foreach ( $results as $gallery ) {
1160 - $galleries[$gallery['id']] = [
1161 - 'name' => $gallery['name'],
1162 - 'description' => $gallery['description'],
1163 - 'layout' => $gallery['layout'],
1164 - 'medias' => maybe_unserialize( $gallery['medias'] ),
1165 - 'lead_image_id' => $gallery['lead_image_id'],
1166 - 'order_by' => $gallery['order_by'],
1167 - 'is_post_mode' => ( bool )$gallery['is_post_mode'],
1168 - 'dynamic_source' => $gallery['dynamic_source'],
1169 - 'hero' => ( bool )$gallery['is_hero_mode'],
1170 - 'posts' => $gallery['posts'] ? maybe_unserialize( $gallery['posts'] ) : null,
1171 - 'latest_posts' => $gallery['latest_posts'],
1172 - 'tags' => $gallery['tags'] ? unserialize( $gallery['tags'] ) : null,
1173 - 'dynamic_source' => $gallery['dynamic_source'],
1174 - 'rml' => $gallery['rml'] ?? null,
1175 - 'updated' => strtotime( $gallery['updated_at'] )
1176 - ];
1177 - }
1178 - return $galleries;
1179 - }
1180 -
1181 - public function get_galleries( $offset = 0, $limit = 10, $order = 'DESC', $sort = null, $page = 1, $search = '' ) {
1182 - global $wpdb;
1183 - $shortcodes_table = $wpdb->prefix . 'mgl_gallery_shortcodes';
1184 - Meow_MGL_Migrations::check_db();
1185 -
1186 - // Get total count
1187 - $total = 0;
1188 - if ( empty( $search ) ) {
1189 - $total = $wpdb->get_var( "SELECT COUNT( * ) FROM $shortcodes_table" );
1190 - } else {
1191 - $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $shortcodes_table WHERE name LIKE %s", '%' . $wpdb->esc_like( $search ) . '%' ) );
1192 - }
1193 -
1194 - // Calculate offset based on page if provided
1195 - if ($page > 1 && $offset === 0) {
1196 - $offset = ($page - 1) * $limit;
1197 - }
1198 -
1199 - // Get shortcodes with pagination and sorting
1200 - $sort_accessor_to_column = [
1201 - 'info' => 'name',
1202 - 'updated' => 'updated_at',
1203 - 'rank' => 'pref_rank',
1204 - ];
1205 -
1206 - $sort = $sort_accessor_to_column[$sort] ?? 'pref_rank';
1207 - $order = in_array( strtoupper( $order ), ['ASC', 'DESC'] ) ? strtoupper( $order ) : 'DESC';
1208 -
1209 - // Sort by rank DESC first, then by updated_at for equal ranks
1210 - $query = $wpdb->prepare(
1211 - "SELECT * FROM $shortcodes_table WHERE name LIKE %s ORDER BY $sort $order, updated_at DESC LIMIT %d, %d",
1212 - '%' . $wpdb->esc_like( $search ) . '%', $offset, $limit
1213 - );
1214 -
1215 - $results = $wpdb->get_results( $query, ARRAY_A );
1216 - $shortcodes = [];
1217 -
1218 - foreach ( $results as $gallery ) {
1219 - // Transform database format to match expected format
1220 - $shortcodes[$gallery['id']] = [
1221 - 'name' => $gallery['name'],
1222 - 'description' => $gallery['description'],
1223 - 'layout' => $gallery['layout'],
1224 - 'medias' => maybe_unserialize( $gallery['medias'] ),
1225 - 'lead_image_id' => $gallery['lead_image_id'],
1226 - 'order_by' => $gallery['order_by'],
1227 - 'is_post_mode' => ( bool )$gallery['is_post_mode'],
1228 - 'hero' => ( bool )$gallery['is_hero_mode'],
1229 - 'posts' => $gallery['posts'] ? maybe_unserialize( $gallery['posts'] ) : null,
1230 - 'latest_posts' => $gallery['latest_posts'],
1231 - 'tags' => $gallery['tags'] ? unserialize( $gallery['tags'] ) : null,
1232 - 'dynamic_source' => $gallery['dynamic_source'],
1233 - 'rml' => $gallery['rml'] ?? null,
1234 - 'rank' => intval( $gallery['pref_rank'] ?? 0 ),
1235 - 'updated' => strtotime( $gallery['updated_at'] )
1236 - ];
1237 - }
1238 -
1239 - return [
1240 - 'total' => $total,
1241 - 'galleries' => $shortcodes
1242 - ];
1243 - }
1244 -
1245 - public function get_collection_by_id( $id ) {
1246 - global $wpdb;
1247 - $collections_table = $wpdb->prefix . 'mgl_collections';
1248 - $shortcodes_table = $wpdb->prefix . 'mgl_gallery_shortcodes';
1249 -
1250 - // Get the collection
1251 - $collection = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $collections_table WHERE id = %d", $id ), ARRAY_A );
1252 - if ( !$collection ) {
1253 - throw new Exception( __( 'Collection not found.', MGL_DOMAIN ));
1254 - }
1255 - $collection['galleries_ids'] = unserialize( $collection['galleries_ids'] );
1256 -
1257 - // Get the associated galleries
1258 - $galleries = [];
1259 - if ( !empty( $collection['galleries_ids'] )) {
1260 - $galleries_ids_str = "'" . implode( "','", array_map( 'esc_sql', $collection['galleries_ids'] )) . "'";
1261 - $galleries_query = "SELECT * FROM $shortcodes_table WHERE id IN ( $galleries_ids_str )";
1262 - $galleries_data = $wpdb->get_results( $galleries_query, ARRAY_A );
1263 -
1264 - foreach ( $galleries_data as $gallery ) {
1265 - // Transform database format to match expected format
1266 - $galleries[] = [
1267 - 'id' => $gallery['id'],
1268 - 'name' => $gallery['name'],
1269 - 'description' => $gallery['description'],
1270 - 'layout' => $gallery['layout'],
1271 - 'medias' => unserialize( $gallery['medias'] ),
1272 - 'lead_image_id' => $gallery['lead_image_id'],
1273 - 'order_by' => $gallery['order_by'],
1274 - 'is_post_mode' => ( bool )$gallery['is_post_mode'],
1275 - 'hero' => ( bool )$gallery['is_hero_mode'],
1276 - 'posts' => $gallery['posts'] ? unserialize( $gallery['posts'] ) : null,
1277 - 'latest_posts' => $gallery['latest_posts'],
1278 - 'updated' => strtotime( $gallery['updated_at'] )
1279 - ];
1280 - }
1281 -
1282 - // Format collection data
1283 - $collection['galleries'] = $galleries;
1284 - }
1285 -
1286 - return $collection;
1287 - }
1288 -
1289 - public function get_collections( $offset = 0, $limit = 10, $order = 'DESC', $page = 1, $search = '' ) {
1290 - global $wpdb;
1291 - $collections_table = $wpdb->prefix . 'mgl_collections';
1292 - $shortcodes_table = $wpdb->prefix . 'mgl_gallery_shortcodes';
1293 - Meow_MGL_Migrations::check_db();
1294 -
1295 - // Get total count
1296 - if( empty( $search ) ) {
1297 - $total = $wpdb->get_var( "SELECT COUNT( * ) FROM $collections_table" );
1298 - } else {
1299 - $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $collections_table WHERE name LIKE %s", '%' . $wpdb->esc_like( $search ) . '%' ) );
1300 - }
1301 - // Calculate offset based on page if provided
1302 - if ($page > 1 && $offset === 0) {
1303 - $offset = ($page - 1) * $limit;
1304 - }
1305 -
1306 - // Get collections with pagination and sorting
1307 - $query = $wpdb->prepare(
1308 - "SELECT * FROM $collections_table WHERE name LIKE %s ORDER BY updated_at $order LIMIT %d, %d",
1309 - '%' . $wpdb->esc_like( $search ) . '%', $offset, $limit
1310 - );
1311 -
1312 - $collections = $wpdb->get_results( $query, ARRAY_A );
1313 - $result = [];
1314 -
1315 - foreach ( $collections as $collection ) {
1316 - $collection_id = $collection['id'];
1317 - $galleries_ids = unserialize( $collection['galleries_ids'] );
1318 -
1319 - // Get the associated galleries
1320 - $galleries = [];
1321 - if ( !empty( $galleries_ids )) {
1322 - $galleries_ids_str = "'" . implode( "','", array_map( 'esc_sql', $galleries_ids )) . "'";
1323 - $galleries_query = "SELECT * FROM $shortcodes_table WHERE id IN ( $galleries_ids_str )";
1324 - $galleries_data = $wpdb->get_results( $galleries_query, ARRAY_A );
1325 -
1326 - foreach ( $galleries_data as $gallery ) {
1327 - // Transform database format to match expected format
1328 - $gallery_item = [
1329 - 'id' => $gallery['id'],
1330 - 'name' => $gallery['name'],
1331 - 'description' => $gallery['description'],
1332 - 'layout' => $gallery['layout'],
1333 - 'medias' => unserialize( $gallery['medias'] ),
1334 - 'lead_image_id' => $gallery['lead_image_id'],
1335 - 'order_by' => $gallery['order_by'],
1336 - 'is_post_mode' => ( bool )$gallery['is_post_mode'],
1337 - 'hero' => ( bool )$gallery['is_hero_mode'],
1338 - 'posts' => $gallery['posts'] ? unserialize( $gallery['posts'] ) : null,
1339 - 'latest_posts' => $gallery['latest_posts'],
1340 - 'tags' => $gallery['tags'] ? unserialize( $gallery['tags'] ) : null,
1341 - 'dynamic_source' => $gallery['dynamic_source'],
1342 - 'updated' => strtotime( $gallery['updated_at'] )
1343 - ];
1344 - $galleries[] = $gallery_item;
1345 - }
1346 - }
1347 -
1348 - // Format collection data
1349 - $result[$collection_id] = [
1350 - 'name' => $collection['name'],
1351 - 'description' => $collection['description'],
1352 - 'layout' => $collection['layout'],
1353 - 'galleries_ids' => $galleries_ids,
1354 - 'galleries' => $galleries,
1355 - 'updated' => strtotime( $collection['updated_at'] )
1356 - ];
1357 - }
1358 -
1359 - return [
1360 - 'total' => $total,
1361 - 'collections' => $result
1362 - ];
1363 - }
1364 -
1365 129 }
1366 130
1367 131 ?>