WordPress

javascript — Blok galerii murarskich działa w edytorze bloków, ale nie w edytorze szablonów

  • 12 sierpnia, 2023
  • 3 min read
javascript — Blok galerii murarskich działa w edytorze bloków, ale nie w edytorze szablonów


Buduję niestandardowy blok galerii Masonry (wersja inna niż jQuery) i udało mi się sprawić, by działał w edytorze bloków. Używam WP 6.3. To jest mniej więcej kod:

JS:

const containerRef = useRef(null);
const {
    attributes: { items, columns, gap },
    setAttributes,
} = props;

useEffect(() => {
    var msnry;
    if (containerRef.current) {
        imagesLoaded(containerRef.current, function () {
            msnry = new Masonry(containerRef.current, {
                itemSelector: '.gallery-item',
                columnWidth: '.grid-sizer',
                percentPosition: true,
                gutter: parseInt(gap),
            });
        });
    }

    return () => {
        msnry?.destroy();
    }

}, [items, columns, gap]);

....

const displayItems = (items) => {
    return (
        items.map((item, index) => {
            return (
                <div className="gallery-item" key={index}>
                    <figure>
                        <img className={`wp-image-${item.id}`} src={item.url} alt={item.alt} key={item.id} />
                    </figure>
                </div>
            )
        })
    )
};

{items.length > 0 ?
    <div {...blockProps}>
        <div className="gallery-items" style={{ '--gap': gap }} ref={containerRef}>
            <div className="grid-sizer"></div>
            {displayItems(items)}
        </div>
    </div>
}

SCSS:

.wp-block-my-masonry-gallery {
    .gallery-items {
        --gap: 10px;
        display: flex;
        flex-wrap: wrap;
        gap: var(--gap);
    }
    @for $i from 2 through 8 {
        &.columns-#{$i} {
            .gallery-item,
            .grid-sizer {
                width: calc(percentage(math.div(1, $i)) - var(--gap) + (var(--gap) / $i));
            }
        }
    }
}

blok.json

{
    "apiVersion": 3,
    "name": "my/masonry-gallery",
    "title": "My Masonry Gallery",
    "attributes": {
        "items": {
            "type": "array",
            "default": []
        },
        "columns": {
            "type": "number",
            "minimum": 1,
            "maximum": 8,
            "default": 3
        },
        "gap": {
            "type": "string",
            "default": "10px"
        }
    },
    "editorScript": [
        "file:./index.js",
        "imagesloaded",
        "masonry"
    ],
    "viewScript": [
        "file:./view.js",
        "imagesloaded",
        "masonry"
    ],
    "style": [
        "file:./style-index.css",
        "file:./view.css"
    ],
    "editorStyle": "file:./index.css"
}

Jak powiedziałem wcześniej, blok działa w edytorze bloków, ale kiedy próbuję tego w nowym edytorze szablonów FSE, biblioteka Masonry nie jest poprawnie inicjowana, ponieważ wysokość kontenera Masonry jest ustawiona na zero, w związku z czym obrazy galerii nakładają się kolejne bloki na ekranie.

Warto przeczytać!  Motyw WooCommerce dla niszowego sklepu eCommerce: przewodnik

Blok w edytorze bloków:

wprowadź tutaj opis obrazu

Zablokuj w edytorze szablonów FSE:

wprowadź tutaj opis obrazu

Ktoś wskazał mi następujący post, który wspomina, że ​​edytor szablonów jest ładowany w ramce iframe, aby odizolować go od reszty ekranu administracyjnego i może powodować problemy z bibliotekami innymi niż React i sugerować pewne zmiany, aby działały w edytorze iframe:

Dokonałem refaktoryzacji kodu, korzystając z przykładów w poście, ale otrzymuję takie same wyniki jak poprzednio:

const containerRef = useRefEffect((element) => {
    var msnry;
    imagesLoaded(element, function () {
        msnry = new Masonry(element, {
            itemSelector: '.gallery-item',
            columnWidth: '.grid-sizer',
            percentPosition: true,
            gutter: parseInt(gap),
        });
    });

    return () => {
        msnry?.destroy();
    }

}, [items, columns, gap]);

Kierując się sugestiami @stokesman, bez powodzenia dokonałem refaktoryzacji kodu do następującego:

const containerRef = useRefEffect((element) => {
    var msnry;
    
    const { ownerDocument } = element;
    const { defaultView } = ownerDocument;

    if ( ! defaultView.imagesLoaded || ! defaultView.Masonry ) {
        return;
    }

    defaultView.imagesLoaded(element, function () {
        msnry = new defaultView.Masonry(element, {
            itemSelector: '.gallery-item',
            columnWidth: '.grid-sizer',
            percentPosition: true,
            gutter: parseInt(gap),
        });
    });

    return () => {
        msnry?.destroy();
    }

}, [items, columns, gap]);

The if ( ! defaultView.imagesLoaded || ! defaultView.Masonry ) sprawdzenie nigdy nie daje wartości false a część murowana nigdy nie jest wykonywana.

Warto przeczytać!  przekierowanie - 301 nie działa z wieloma witrynami

Jakieś pomysły?

AKTUALIZACJA (20.02.2024):

Aby wstawić skrypty załadowane masonry i obrazami do elementu iframe, tak aby można było z nich korzystać z poziomu elementu iframe, należy je dodać do script podpora (nie editorScript rekwizyt) w block.json plik. W przeciwnym razie z jakiegoś powodu są ładowane POZA ramką iframe.

...
"script": [
    "imagesloaded",
    "masonry"
],
"editorScript": "file:./index.js",
"viewScript": "file:./view.js",
...


Źródło