| @@ -77,8 +77,34 @@ | ||
| 77 | 77 | function collection() { |
| 78 | 78 | 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."; |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | + // Gallery and collection IDs are plain identifiers (generate_uniqid(), stored as varchar). | |
| 82 | + // Anything else is rejected, and rejected rather than stripped: stripping could turn a crafted | |
| 83 | + // ID into a different existing one. Security: esc_attr() does NOT escape "]", so an ID coming | |
| 84 | + // from a request and concatenated into a shortcode string could close the tag and run | |
| 85 | + // arbitrary shortcodes. Keep IDs on this charset and never build a shortcode string from them. | |
| 86 | + public static function sanitize_id( $id ) { | |
| 87 | + if ( !is_scalar( $id ) ) { | |
| 88 | + return ''; | |
| 89 | + } | |
| 90 | + $id = (string) $id; | |
| 91 | + return preg_match( '/^[A-Za-z0-9_-]+$/', $id ) ? $id : ''; | |
| 92 | + } | |
| 93 | + | |
| 94 | + // Renders a collection from its ID. Deliberately calls the handler directly instead of going | |
| 95 | + // through do_shortcode(): there is no shortcode string to inject into that way. | |
| 96 | + public function render_collection( $id, $is_preview = false ) { | |
| 97 | + $id = self::sanitize_id( $id ); | |
| 98 | + if ( $id === '' ) { | |
| 99 | + return "<p class='meow-error'><b>Meow Gallery:</b> This collection ID is not valid.</p>"; | |
| 100 | + } | |
| 101 | + if ( $this->pro_module && $this->pro ) { | |
| 102 | + return $this->pro->collection( array( 'id' => $id ), $is_preview ); | |
| 103 | + } | |
| 104 | + return $this->collection(); | |
| 105 | + } | |
| 106 | + | |
| 81 | 107 | public function can_access_settings() { |
| 82 | 108 | return apply_filters( 'mgl_allow_setup', current_user_can( 'manage_options' ) ); |
| 83 | 109 | } |
| 84 | 110 | |
| @@ -143,11 +169,11 @@ | ||
| 143 | 169 | if ( isset( $atts['meow'] ) && $atts['meow'] === 'false' ) { |
| 144 | 170 | return gallery_shortcode( $atts ); |
| 145 | 171 | } |
| 146 | 172 | |
| 147 | - // If the attributes contain "collection" then use the collection shortcode instead | |
| 173 | + // If the attributes contain "collection" then render that collection instead | |
| 148 | 174 | if ( isset( $atts['collection'] ) && !empty( $atts['collection'] ) ) { |
| 149 | - return do_shortcode( '[meow-collection id="' . $atts['collection'] . '"]' ); | |
| 175 | + return $this->render_collection( $atts['collection'] ); | |
| 150 | 176 | } |
| 151 | 177 | |
| 152 | 178 | $image_ids = array(); |
| 153 | 179 | $layout = ''; |
| @@ -174,9 +200,10 @@ | ||
| 174 | 200 | try { |
| 175 | 201 | $shortcode = $this->get_gallery_by_id( $shortcode_id ); |
| 176 | 202 | } |
| 177 | 203 | catch ( Exception $e ) { |
| 178 | - return "<p class='meow-error'><b>Meow Gallery:</b> This ID wasn't found in the Gallery Manager. (ID: $shortcode_id). " . $e->getMessage() . "</p>"; | |
| 204 | + $safe_id = esc_html( is_scalar( $shortcode_id ) ? $shortcode_id : '' ); | |
| 205 | + return "<p class='meow-error'><b>Meow Gallery:</b> This ID wasn't found in the Gallery Manager. (ID: $safe_id). " . esc_html( $e->getMessage() ) . "</p>"; | |
| 179 | 206 | } |
| 180 | 207 | |
| 181 | 208 | if ( !isset( $shortcode['medias'] ) || !isset( $shortcode['medias']['thumbnail_ids'])) { |
| 182 | 209 | return "<p class='meow-error'><b>Meow Gallery:</b> Thumbnail IDs not found.</p>"; |
| @@ -995,9 +1022,16 @@ | ||
| 995 | 1022 | $mergedArray['featured_post_url'] = get_permalink( $post_id ); |
| 996 | 1023 | |
| 997 | 1024 | } |
| 998 | 1025 | |
| 999 | - $result[] = array_merge( $image, $mergedArray, $orientation ); | |
| 1026 | + // Everything above can read the full attachment metadata, but it ends up in the page as | |
| 1027 | + // data-gallery-images, and the front-end only needs the dimensions. Every size and the EXIF | |
| 1028 | + // were bloating the HTML of big galleries (wp.org forum, 2026-09). The map layout returns | |
| 1029 | + // earlier with its own data. | |
| 1030 | + $item = array_merge( $image, $mergedArray, $orientation ); | |
| 1031 | + $meta = is_array( $image['meta'] ) ? $image['meta'] : []; | |
| 1032 | + $item['meta'] = [ 'width' => $meta['width'] ?? null, 'height' => $meta['height'] ?? null ]; | |
| 1033 | + $result[] = $item; | |
| 1000 | 1034 | } |
| 1001 | 1035 | |
| 1002 | 1036 | $this->gallery_process = $previous_gallery_process; |
| 1003 | 1037 | $this->gallery_layout = $previous_gallery_layout; |