'boolean', 'default' => false, ); } return $settings; } /** * Override gallery block render callback. */ public function override_callback( $settings, $metadata ) { if ( 'core/gallery' === $metadata['name'] ) { $settings['render_callback'] = array( $this, 'render_callback' ); } return $settings; } /** * Enqueue editor scripts and styles. */ public function enqueue_editor_assets() { wp_enqueue_script( 'brandy/gallery-masonry-display', BRANDY_TEMPLATE_URL . '/inc/BlockSettings/GalleryMasonryDisplay/script.js', array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ), BRANDY_SCRIPT_VERSION, true ); // Enqueue styles for editor preview wp_register_style( 'brandy/gallery-masonry-display', false, array(), BRANDY_SCRIPT_VERSION ); wp_enqueue_style( 'brandy/gallery-masonry-display' ); wp_add_inline_style( 'brandy/gallery-masonry-display', $this->get_css() ); } /** * Conditionally enqueue frontend styles (only when masonry gallery is used). */ private function maybe_enqueue_frontend_styles() { if ( $this->styles_enqueued || is_admin() ) { return; } $this->styles_enqueued = true; wp_register_style( 'brandy/gallery-masonry-display', false, array(), BRANDY_SCRIPT_VERSION ); wp_enqueue_style( 'brandy/gallery-masonry-display' ); wp_add_inline_style( 'brandy/gallery-masonry-display', $this->get_css() ); } /** * Render gallery block with masonry support. * * @param array $attributes Block attributes. * @param string $content Block content. * @param object $block Block instance. * @return string Rendered block HTML. */ public function render_callback( $attributes, $content, $block ) { // Use default gallery render if available if ( function_exists( 'block_core_gallery_render' ) ) { $gallery_content = block_core_gallery_render( $attributes, $content ); } else { return $content; } // Apply masonry modifications if enabled if ( empty( $attributes['masonryDisplay'] ) ) { return $gallery_content; } // Enqueue styles only when masonry is actually used $this->maybe_enqueue_frontend_styles(); $processor = new \WP_HTML_Tag_Processor( $gallery_content ); // Get column count from gallery attributes, default to 3 $columns = isset( $attributes['columns'] ) && $attributes['columns'] > 0 ? absint( $attributes['columns'] ) : 3; if ( $processor->next_tag( array( 'class_name' => 'wp-block-gallery' ) ) ) { $processor->add_class( 'has-masonry-display' ); $processor->set_attribute( 'data-masonry-columns', $columns ); // Add CSS custom property for column count $existing_style = $processor->get_attribute( 'style' ) ?? ''; $new_style = trim( $existing_style . ' --masonry-columns: ' . $columns . ';' ); $processor->set_attribute( 'style', $new_style ); $gallery_content = $processor->get_updated_html(); } return $gallery_content; } public function get_css() { ob_start(); ?> /** * Gallery Masonry Display Styles * Uses CSS columns for masonry layout (Pinterest-style vertical flow) * * @package Brandy\BlockSettings\GalleryMasonryDisplay */ /* ========================================================================== Container - Override WordPress gallery flexbox with CSS columns ========================================================================== */ .wp-block-gallery.has-masonry-display, .wp-block-gallery.has-masonry-display.is-layout-flex, .wp-block-gallery.has-masonry-display.is-layout-constrained { /* Reset flexbox layout */ display: block !important; flex-wrap: unset !important; flex-direction: unset !important; align-items: unset !important; justify-content: unset !important; /* CSS Columns for masonry */ column-count: var(--masonry-columns, 3); column-gap: var(--wp--style--block-gap, 1rem); column-fill: balance; /* Don't balance - let columns fill naturally */ /* Reset other defaults */ list-style-type: none; margin: 0; padding: 0; width: 100%; box-sizing: border-box; } /* Column count via data attribute (highest specificity) */ .wp-block-gallery.has-masonry-display[data-masonry-columns="1"] { column-count: 1 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="2"] { column-count: 2 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="3"] { column-count: 3 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="4"] { column-count: 4 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="5"] { column-count: 5 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="6"] { column-count: 6 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="7"] { column-count: 7 !important; } .wp-block-gallery.has-masonry-display[data-masonry-columns="8"] { column-count: 8 !important; } /* Column count via WordPress columns class (fallback) */ .wp-block-gallery.has-masonry-display.columns-1 { column-count: 1; } .wp-block-gallery.has-masonry-display.columns-2 { column-count: 2; } .wp-block-gallery.has-masonry-display.columns-3 { column-count: 3; } .wp-block-gallery.has-masonry-display.columns-4 { column-count: 4; } .wp-block-gallery.has-masonry-display.columns-5 { column-count: 5; } .wp-block-gallery.has-masonry-display.columns-6 { column-count: 6; } .wp-block-gallery.has-masonry-display.columns-7 { column-count: 7; } .wp-block-gallery.has-masonry-display.columns-8 { column-count: 8; } /* ========================================================================== Responsive breakpoints ========================================================================== */ @media (max-width: 781px) { .wp-block-gallery.has-masonry-display:not([data-masonry-columns="1"]) { column-count: 2 !important; } } @media (max-width: 480px) { .wp-block-gallery.has-masonry-display { column-count: 1 !important; } } /* ========================================================================== Gallery Items - Both old (.blocks-gallery-item) and new (figure.wp-block-image) ========================================================================== */ /* Old gallery structure */ .wp-block-gallery.has-masonry-display .blocks-gallery-item { display: block !important; width: 100% !important; margin: 0 0 var(--wp--style--block-gap, 1rem) 0 !important; padding: 0 !important; /* Prevent item from breaking across columns */ break-inside: avoid !important; page-break-inside: avoid !important; -webkit-column-break-inside: avoid !important; /* Reset flexbox properties */ flex: unset !important; flex-grow: unset !important; flex-shrink: unset !important; flex-basis: unset !important; /* Proper sizing */ height: auto !important; min-height: unset !important; max-height: none !important; box-sizing: border-box; } /* New gallery structure (has-nested-images) */ .wp-block-gallery.has-masonry-display.has-nested-images figure.wp-block-image { display: block !important; width: 100% !important; margin: 0 0 var(--wp--style--block-gap, 1rem) 0 !important; padding: 0 !important; /* Prevent item from breaking across columns */ break-inside: avoid !important; page-break-inside: avoid !important; -webkit-column-break-inside: avoid !important; /* Reset flexbox properties */ flex: unset !important; flex-grow: unset !important; flex-shrink: unset !important; flex-basis: unset !important; /* Proper sizing - key for natural aspect ratio */ height: auto !important; min-height: unset !important; max-height: none !important; aspect-ratio: not-set !important; box-sizing: border-box; } /* ========================================================================== Inner containers (figures, links, divs) ========================================================================== */ .wp-block-gallery.has-masonry-display .blocks-gallery-item figure { display: block !important; width: 100% !important; height: auto !important; margin: 0 !important; padding: 0 !important; /* Reset flex */ flex: unset !important; flex-direction: unset !important; flex-grow: unset !important; align-items: unset !important; justify-content: unset !important; } .wp-block-gallery.has-masonry-display.has-nested-images figure.wp-block-image > a, .wp-block-gallery.has-masonry-display.has-nested-images figure.wp-block-image > div { display: block !important; width: 100% !important; height: auto !important; margin: 0 !important; padding: 0 !important; } /* ========================================================================== Images - Natural aspect ratio is key for masonry ========================================================================== */ .wp-block-gallery.has-masonry-display .blocks-gallery-item img, .wp-block-gallery.has-masonry-display.has-nested-images figure.wp-block-image img { display: block !important; width: 100% !important; height: auto !important; max-width: 100% !important; /* Remove forced dimensions */ min-height: unset !important; max-height: none !important; aspect-ratio: not-set !important; /* Cover for any crops, but auto height preserves ratio */ object-fit: cover; box-sizing: border-box; } /* ========================================================================== Captions ========================================================================== */ .wp-block-gallery.has-masonry-display figcaption, .wp-block-gallery.has-masonry-display .blocks-gallery-item__caption { position: relative !important; margin-top: 0.5rem; font-size: 0.875rem; text-align: center; /* Reset absolute positioning if WordPress applies it */ bottom: unset !important; left: unset !important; right: unset !important; } /* ========================================================================== Editor-specific adjustments ========================================================================== */ .block-editor-block-list__block .wp-block-gallery.has-masonry-display, .editor-styles-wrapper .wp-block-gallery.has-masonry-display { display: block !important; column-fill: balance; } .block-editor-block-list__block .wp-block-gallery.has-masonry-display figure.wp-block-image, .editor-styles-wrapper .wp-block-gallery.has-masonry-display figure.wp-block-image { display: block !important; width: 100% !important; height: auto !important; break-inside: avoid !important; }