Шаблоны не отображаются в пользовательском компоненте редактора Гутенберга для отображения Гутенберга повсюду.

Вопрос или проблема

Я написал пользовательский React-компонент “Gutenberg”, чтобы использовать его везде с React, просто используя <Gutenberg value={blocks} onChange={setBlocks} />

Была проблема с блоками, никакие пользовательские блоки не отображались в библиотеке блоков. Я решил эту проблему, используя встроенные скрипты, которые вы можете увидеть ниже

Сейчас у меня аналогичная проблема с шаблонами блоков, enter image description here я не могу видеть никаких шаблонов, но они видны на обычной странице редактирования постов.

Вот мой код:

import React, {useState, useEffect, useRef} from 'react';
import {SlotFillProvider, Button, Popover} from '@wordpress/components';
import {
    BlockEditorProvider,
    BlockList,
    // @ts-ignore
    BlockTools,
    BlockInspector,
    WritingFlow,
    ObserveTyping,
    // @ts-ignore
    __experimentalLibrary as BlockLibrary,
    // @ts-ignore
    __experimentalListView as ListView,
    Inserter,
    BlockToolbar,
    // @ts-ignore
    TabbedSidebar,
} from '@wordpress/block-editor';
import { registerCoreBlocks } from '@wordpress/block-library';  // Ensure core blocks are registered
// @ts-ignore
import { ShortcutProvider } from '@wordpress/keyboard-shortcuts';
// @ts-ignore
import { InterfaceSkeleton } from '@wordpress/interface';
import { redo as redoIcon, undo as undoIcon, drawerLeft, drawerRight, plus, closeSmall, listView } from '@wordpress/icons';
import { __, isRTL } from '@wordpress/i18n';
import {Icon} from "@components";
import {useAppContext} from "@hooks";

registerCoreBlocks();

interface GutenbergProps {
    value: string;
    onChange: (value: string) => void
    toggleFullScreen?: () => void
    isFullScreen?: boolean
    label?: string
}

const Gutenberg: React.FC<GutenbergProps> = ({
    value,
    onChange,
    toggleFullScreen = () => {},
    isFullScreen = false,
    label = __('Block Editor', 'levcharity-editor')
}) => {
    // @ts-ignore
    const [blocks, setBlocks] = useState(wp.blocks.parse(value || '<!-- wp:paragraph --> <p></p> <!-- /wp:paragraph -->'));
    const [history, setHistory] = useState<{ past: any[], future: any[] }>({ past: [], future: [] });
    const [isRightSidebarOpen, setIsRightSidebarOpen] = useState(false);
    const [isListViewOpen, setIsListViewOpen] = useState(false);
    const [isInserterOpen, setIsInserterOpen] = useState(false);
    const [localValue, setLocalValue] = useState(value || '<!-- wp:paragraph --> <p></p> <!-- /wp:paragraph -->');
    const [ dropZoneElement, setDropZoneElement ] = useState( null );
    const {data} = useAppContext();

    useEffect(() => {
        if (value && localValue !== value) {
            // @ts-ignore
            setBlocks(wp.blocks.parse(value || '<!-- wp:paragraph --> <p></p> <!-- /wp:paragraph -->')); // Parse initial value into blocks
        }
    }, [value]);

    const handleChange = (newBlocks: any[]) => {
        setHistory({
            past: [...history.past, blocks],
            future: [],
        });
        setBlocks(newBlocks);
        // @ts-ignore
        setLocalValue(wp.blocks.serialize(newBlocks)); // Serialize blocks on change
        // @ts-ignore
        onChange(wp.blocks.serialize(newBlocks)); // Serialize blocks on change
    };

    const undo = () => {
        if (history.past.length === 0) return;
        const previous = history.past[history.past.length - 1];
        const newPast = history.past.slice(0, history.past.length - 1);
        setHistory({
            past: newPast,
            future: [blocks, ...history.future],
        });
        setBlocks(previous);
    };

    const redo = () => {
        if (history.future.length === 0) return;
        const next = history.future[0];
        const newFuture = history.future.slice(1);
        setHistory({
            past: [...history.past, blocks],
            future: newFuture,
        });
        setBlocks(next);
    };

    const canUndo = history.past.length > 0;
    const canRedo = history.future.length > 0;

    const toggleRightSidebar = () => {
        setIsRightSidebarOpen(!isRightSidebarOpen);
    };

    const toggleListView = ()=> {
        setIsListViewOpen(!isListViewOpen);
        if (!isListViewOpen && isInserterOpen) {
            setIsInserterOpen(false);
        }
    }

    const toggleInserter = ()=> {
        setIsInserterOpen(!isInserterOpen);
        if (!isInserterOpen && setIsListViewOpen) {
            setIsListViewOpen(false);
        }
    }

    // @ts-ignore
    // @ts-ignore
    // @ts-ignore
    return (
        <div className={"levcharity-gutenberg-editor" + (isListViewOpen || isInserterOpen ? ' secondary-sidebar-open' : '') + (isRightSidebarOpen ? ' sidebar-open' : '')}>
            <ShortcutProvider>
                <SlotFillProvider>
                    <BlockEditorProvider
                        value={blocks}
                        onInput={handleChange}
                        onChange={handleChange}
                        settings={{
                            maxWidth: 1120,

                        }}
                    >
                        <InterfaceSkeleton
                            header={
                                <div className="block-editor-header">
                                    <div className="left-side-buttons header-buttons">
                                        <Button onClick={toggleInserter} variant={'primary'} isPressed={isInserterOpen} icon={ !isInserterOpen ? plus : closeSmall }></Button>
                                        <div className={"history-buttons header-buttons"}>
                                            <Button onClick={canUndo ? undo : undefined} disabled={!canUndo} icon={ ! isRTL() ? undoIcon : redoIcon }></Button>
                                            <Button onClick={canRedo ? redo : undefined} disabled={!canRedo} icon={ ! isRTL() ? redoIcon : undoIcon }></Button>
                                        </div>
                                        <Button onClick={toggleListView} isPressed={isListViewOpen} icon={ listView }></Button>
                                    </div>
                                    <h2 className="header-heading levcharity_heading">{label}</h2>
                                    <div className="right-side-buttons header-buttons">
                                        <Button onClick={toggleRightSidebar} isPressed={isRightSidebarOpen} icon={ isRTL() ? drawerLeft : drawerRight }></Button>
                                        {toggleFullScreen && <Button onClick={toggleFullScreen} isPressed={isFullScreen} icon={ !isFullScreen ? <Icon name={"FullscreenOutlined"} /> : <Icon name={"FullscreenExitOutlined"} /> }></Button>}
                                    </div>
                                </div>
                            }
                            secondarySidebar={
                                <>
                                    {isListViewOpen && <div className="editor-list-view-sidebar__list-view-container" style={{minWidth: 350, maxWidth: 350}}>
                                        <div className="editor-list-view-sidebar__list-view-panel-content">
                                            <ListView
                                                dropZoneElement={dropZoneElement}
                                            />
                                        </div>
                                    </div>}
                                    {isInserterOpen && <BlockLibrary rootClientId={null} onClose={() => setIsInserterOpen(false)}/>}
                                </>
                            }
                            sidebar={isRightSidebarOpen && <div style={{minWidth: 350, maxWidth: 350}}><BlockInspector/></div>}
                            content={
                                <div className="editor-body">
                                    <BlockTools>
                                        <div className="editor-styles-wrapper" style={{background: 'white'}}>
                                            <WritingFlow>
                                                <ObserveTyping>
                                                    {/* @ts-ignore */}
                                                    <BlockList blocks={blocks}/>
                                                </ObserveTyping>
                                            </WritingFlow>
                                        </div>
                                    </BlockTools>
                                </div>
                            }
                        />
                        {/* @ts-ignore */}
                        <Popover.Slot />
                    </BlockEditorProvider>
                </SlotFillProvider>
            </ShortcutProvider>
        </div>
    );
}

export default Gutenberg;
class AssetsManager extends BaseManager
{
    protected function addActions(): void
    {
        add_action('admin_enqueue_scripts', [ $this, 'gutenbergSettings' ], 9);
    }

    public function gutenbergSettings(): void
    {
        if (isset($_GET['page']) && $_GET['page'] === 'levcharity-editor' && apply_filters('levcharity_editor_require_gutenberg', false)) {

            $post_id = Helper::getCurrentState('id');
            $post = get_post($post_id);

            if (Helper::getCurrentState('type') === 'post') {
                $block_editor_context = new \WP_Block_Editor_Context( array( 'post' => $post_id ) );
            } else {
                $block_editor_context = new \WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) );
            }
            $custom_settings      = array(
                'siteUrl'                   => site_url(),
                'postsPerPage'              => get_option( 'posts_per_page' ),
                'styles'                    => get_block_editor_theme_styles(),
                'defaultTemplatePartAreas'  => get_allowed_block_template_part_areas(),
                'supportsLayout'            => wp_theme_has_theme_json(),
                'supportsTemplatePartsMode' => ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ),
            );

            $custom_settings['__experimentalAdditionalBlockPatterns']          = \WP_Block_Patterns_Registry::get_instance()->get_all_registered( true );
            $custom_settings['__experimentalAdditionalBlockPatternCategories'] = \WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered( true );

            $editor_settings = get_block_editor_settings( $custom_settings, $block_editor_context );

            wp_add_inline_script(
                'wp-blocks',
                'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');'
            );

            if (Helper::getCurrentState('type') === 'post') {
                wp_add_inline_script(
                    'wp-blocks',
                    sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ) ) ),
                    'after'
                );
            } else {
                wp_add_inline_script(
                    'wp-blocks',
                    sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( isset( $editor_settings['blockCategories'] ) ? $editor_settings['blockCategories'] : array() ) ),
                    'after'
                );
            }

            $block_registry = \WP_Block_Type_Registry::get_instance();
            foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
                // Front-end and editor styles.
                foreach ( $block_type->style_handles as $style_handle ) {
                    wp_enqueue_style( $style_handle );
                }

                // Front-end and editor scripts.
                foreach ( $block_type->script_handles as $script_handle ) {
                    wp_enqueue_script( $script_handle );
                }

                // Editor styles.
                foreach ( $block_type->editor_style_handles as $editor_style_handle ) {
                    wp_enqueue_style( $editor_style_handle );
                }

                // Editor scripts.
                foreach ( $block_type->editor_script_handles as $editor_script_handle ) {
                    wp_enqueue_script( $editor_script_handle );
                }
            }

            enqueue_editor_block_styles_assets();

            $rest_path = rest_get_route_for_post( $post );

            $preload_paths = array(
                '/wp/v2/types?context=view',
                '/wp/v2/taxonomies?context=view',
                '/wp/v2/block-patterns',
                add_query_arg(
                    array(
                        'context'  => 'edit',
                        'per_page' => -1,
                    ),
                    rest_get_route_for_post_type_items( 'wp_block' )
                ),
                add_query_arg( 'context', 'edit', $rest_path ),
                sprintf( '/wp/v2/types/%s?context=edit', $post->post_type ),
                '/wp/v2/users/me',
                array( rest_get_route_for_post_type_items( 'attachment' ), 'OPTIONS' ),
                array( rest_get_route_for_post_type_items( 'page' ), 'OPTIONS' ),
                array( rest_get_route_for_post_type_items( 'wp_block' ), 'OPTIONS' ),
                array( rest_get_route_for_post_type_items( 'wp_template' ), 'OPTIONS' ),
                sprintf( '%s/autosaves?context=edit', $rest_path ),
                '/wp/v2/settings',
                array( '/wp/v2/settings', 'OPTIONS' ),
                '/wp/v2/global-styles/themes/' . get_stylesheet(),
                '/wp/v2/themes?context=edit&status=active',
                '/wp/v2/global-styles/' . \WP_Theme_JSON_Resolver::get_user_global_styles_post_id() . '?context=edit',
            );

            block_editor_rest_api_preload( $preload_paths, $block_editor_context );
        }
    }
}

.

Ответ или решение

Для решения проблемы, связанной с отображением шаблонов блоков в вашем настраиваемом компоненте Gutenberg, необходимо детально проанализировать предоставленный код, чтобы понять, почему ваши блоки паттернов не отображаются в вашей среде редактирования, в отличие от стандартной страницы редактирования постов.

Задействуйте подход FOREST:

Focused (Фокусированный): Ваша проблема касается отображения блоков паттернов исключительно в вашей кастомизированной версии редактора Gutenberg, несмотря на то, что они корректно отображаются в стандартной версии WordPress. Нужно сузить область исследования до работы с отображением паттернов.

Organized (Организованный): Начнем с упрощения понимания, как ваш код обрабатывает паттерны блоков.

Relevant (Актуальный): Мы используем только те детали, которые помогают решить проблему отображения паттернов блоков.

Engaging (Увлекательный): Прямое и информативное разъяснение, что делать далее для исправления проблемы.

Simple (Простой): Избегайте сложных технических терминов, сосредотачиваясь на конкретных шагах и принципах.

Trustworthy (Достоверный): Базируйтесь на пониманиях из документации WordPress и общих практиках.

Решение проблемы:

  1. Загрузите корректно зарегистрированные шаблоны блоков:
    Одним из часто overlooked моментов является корректная регистрация и инициализация библиотеки блоков паттернов. Убедитесь, что паттерны загружаются в нужный момент. Ваш PHP-код пытается регистрировать шаблоны блоков через \WP_Block_Patterns_Registry. Проверьте, что он корректно выполняется во всех необходимых условиях, особенно для вашего настраиваемого интерфейса (например, проверьте условия в if блоках, что они корректные для всех случаев использования).

  2. Проверьте окружение контекста:
    Вызов WP_Block_Editor_Context должен корректно устанавливать контекст среды редактирования. Убедитесь, что передаете правильные параметры при создании объекта контекста.

  3. Серверные блоки и их установка:
    Убедитесь, что установлены все необходимые серверные блоки при помощи wp.blocks.unstable__bootstrapServerSideBlockDefinitions. Это ключевое действие, так как без запущенной действующей конфигурации серверной части, блоки просто не будут распознаваться во фронтенде.

  4. Прелоадинг и маршрутизация REST API:
    Проверьте корректность маршрутов REST API, которые используются для предварительной загрузки блоков и шаблонов блоков. Все ваши маршруты должны быть доступны и корректны, чтобы данные подгружались в редактор.

  5. Код редактора и пользовательские компоненты:
    Когда вы используете кастомный Gutenberg компонент, важно убедиться, что функции, такие как BlockLibrary, получают правильные данные о блоках и их паттернах. Возможно, потребуется встроить вызовы к вашей системе шаблонов блоков непосредственно в место, где библиотека блоков инициируется в React коде.

SEO элементы:

  • Ключевые слова: Gutenberg, шаблоны блоков, редактор WordPress, подгрузка шаблонов, WP Block Editor Context.
  • Оригинальность: Избегайте стандартных рекомендаций, сосредоточьтесь на архитектурных особенностях вашего конкретного случая.
  • Читаемость: Разбивайте информацию на четкие шаги, используйте список для организации инструкций.

Советую также проверять лог ошибок в браузере на предмет отображения Javascript ошибок, которые могут указывать на застопорившееся место в коде. Следование вышеуказанным шагам позволит вам сосредоточиться на ключевых аспектах регистрации и отображения шаблонов блоков в вашем настраиваемом решении Gutenberg.

Оцените материал
Добавить комментарий

Капча загружается...