✅ Notícias, temas e plug-ins da WEB e do WordPress. Aqui compartilhamos dicas e as melhores soluções para sites.

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)

20

Anteriormente, analisamos as opções e configurações de armazenamento usando o WordPress Block Editor (Gutenberg) e expandimos o Create Block Script para permitir pontos finais extras. Neste guia, vamos colocá-los todos juntos para criar uma página de configurações usando componentes do Gutenberg.

A página de configurações que estamos prestes a construir

Mas primeiro, crédito onde o crédito é devido, a inspiração para este guia vai para o artigo Code in WP de Hardeep Asrani: Making a “Plugin Options Page" With Gutenberg Components.

Pré-requisitos

Crie a página de configurações em PHP

Seguindo os guias nos pré-requisitos, abra o arquivo PHP raiz do plugin (neste caso wholesome-plugin.php) e adicione o seguinte:

Registre as configurações

Como nas opções de uso para armazenar dados, adicione as seguintes configurações ao arquivo:

function wholesomecode_wholesome_plugin_register_settings() {
    register_setting(
        'wholesomecode_wholesome_plugin_settings',
        'wholesomecode_wholesome_plugin_example_select',
        [
            'default'      => '',
            'show_in_rest' => true,
            'type'         => 'string',
        ]
    );

    register_setting(
        'wholesomecode_wholesome_plugin_settings',
        'wholesomecode_wholesome_plugin_example_text',
        [
            'default'      => '',
            'show_in_rest' => true,
            'type'         => 'string',
        ]
    );

    register_setting(
        'wholesomecode_wholesome_plugin_settings',
        'wholesomecode_wholesome_plugin_example_text_2',
        [
            'default'      => '',
            'show_in_rest' => true,
            'type'         => 'string',
        ]
    );

    register_setting(
        'wholesomecode_wholesome_plugin_settings',
        'wholesomecode_wholesome_plugin_example_text_3',
        [
            'default'      => '',
            'show_in_rest' => true,
            'type'         => 'string',
        ]
    );

    register_setting(
        'wholesomecode_wholesome_plugin_settings',
        'wholesomecode_wholesome_plugin_example_toggle',
        [
            'default'      => '',
            'show_in_rest' => true,
            'type'         => 'string',
        ]
    );
}
add_action( 'init', 'wholesomecode_wholesome_plugin_register_settings', 10 );

Registre as configurações que acessaremos na página de configurações. Certifique-se de definir show_in_restpara truecada um, para que possam ser acessados ​​via Gutenberg.

Registre a página de configurações

Adicione o bloco de código para registrar a página de configurações:

function wholesomecode_wholesome_plugin_settings_page() {
    add_options_page(
        __( 'Wholesome Plugin Settings', 'wholesome-plugin' ),
        __( 'Wholesome Plugin Settings', 'wholesome-plugin' ),
        'manage_options',
        'wholesome_plugin_settings',
        function() {
            ?>
            <div id="wholesome-plugin-settings"></div>
            <?php
        },
    );
}
add_action( 'admin_menu', 'wholesomecode_wholesome_plugin_settings_page', 10 );

O código acima adiciona uma nova página ao menu de configurações. Observe que tudo o que ele faz é produzir um <div>, é isso que usaremos para renderizar os componentes Gutenberg baseados em React.

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)Item de menu de configurações

Enfileirar recursos de administrador

Para o próximo bloco de código, precisamos ter seguido todas as etapas do guia Adicionar pontos de entrada ao script de criação de bloco . Certifique-se de seguir todas as etapas desse guia antes desta etapa e volte e siga o restante deste guia.

function wholesomecode_wholesome_plugin_admin_scripts() {
    $dir = __DIR__;

    $script_asset_path = "$dir/build/admin.asset.php";
    if (! file_exists( $script_asset_path)) {
        throw new Error(
            'You need to run `npm start` or `npm run build` for the "wholesomecode/wholesome-plugin" block first.'
        );
    }
    $admin_js     = 'build/admin.js';
    $script_asset = require( $script_asset_path );
    wp_enqueue_script(
        'wholesomecode-wholesome-plugin-admin-editor',
        plugins_url( $admin_js, __FILE__ ),
        $script_asset['dependencies'],
        $script_asset['version']
    );
    wp_set_script_translations( 'wholesomecode-wholesome-plugin-block-editor', 'wholesome-plugin' );

    $admin_css = 'build/admin.css';
    wp_enqueue_style(
        'wholesomecode-wholesome-plugin-admin',
        plugins_url( $admin_css, __FILE__ ),
        ['wp-components'],
        filemtime( "$dir/$admin_css") );
}
add_action( 'admin_enqueue_scripts', 'wholesomecode_wholesome_plugin_admin_scripts', 10 );

Construir a página de administração em JavaScript

Se você seguiu todas as etapas no guia Adicionar pontos de entrada ao guia Criar script de bloco, você deve ter um /src/admin.jsarquivo. Abra esse arquivo e exclua seu conteúdo.

Renderize o componente

Lembre-se de executar npm startem seu terminal de acordo com o guia de criação de plug -ins e adicione o abaixo ao seu /src/admin.jsarquivo.

import './admin.scss';
import { Icon } from '@wordpress/components';
import {
    Fragment,
    render,
    Component,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';

class App extends Component {
    constructor() {
        super( ...arguments );
    }

    render() {
        return (<Fragment>
                <div className="wholesome-plugin__header">
                    <div className="wholesome-plugin__container">
                        <div className="wholesome-plugin__title">
                            <h1>{ __( 'Wholesome Plugin Settings', 'wholesome-plugin') } <Icon icon="admin-plugins" /></h1>
                        </div>
                    </div>
                </div>
                <div className="wholesome-plugin__main"></div>
            </Fragment>) }
}

document.addEventListener( 'DOMContentLoaded',() => {
    const htmlOutput = document.getElementById( 'wholesome-plugin-settings' );

    if (htmlOutput) {
        render(
            <App />,
            htmlOutput
        );
    }
});

Se você for para a página de configurações no navegador, agora deverá ver o seguinte:

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)Renderizando componentes na tela de configurações

Adicione os campos de configuração

Lembre-se das etapas extras no guia ‘Usando opções para armazenar dados’? Bem, vamos colar tudo literalmente neste componente, então você deve acabar com algum código que se parece um pouco com isso:

import './admin.scss';

import api from '@wordpress/api';

import {
    Button,
    Icon,
    Panel,
    PanelBody,
    PanelRow,
    Placeholder,
    SelectControl,
    Spinner,
    TextControl,
    ToggleControl,
} from '@wordpress/components';

import {
    Fragment,
    render,
    Component,
} from '@wordpress/element';

import { __ } from '@wordpress/i18n';

class App extends Component {
    constructor() {
        super( ...arguments );

        this.state = {
            exampleSelect: '',
            exampleText: '',
            exampleText2: '',
            exampleText3: '',
            exampleToggle: false,
            isAPILoaded: false,
        };
    }

    componentDidMount() {

        api.loadPromise.then(() => {
            this.settings = new api.models.Settings();

            const { isAPILoaded } = this.state;

            if (isAPILoaded === false) {
                this.settings.fetch().then( (response) => {
                    this.setState( {
                        exampleSelect: response[ 'wholesomecode_wholesome_plugin_example_select' ],
                        exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],
                        exampleText2: response[ 'wholesomecode_wholesome_plugin_example_text_2' ],
                        exampleText3: response[ 'wholesomecode_wholesome_plugin_example_text_3' ],
                        exampleToggle: Boolean( response[ 'wholesomecode_wholesome_plugin_example_toggle' ] ),
                        isAPILoaded: true,
                    } );
                } );
            }
        } );
    }

    render() {
        const {
            exampleSelect,
            exampleText,
            exampleText2,
            exampleText3,
            exampleToggle,
            isAPILoaded,
        } = this.state;

        if (! isAPILoaded) {
            return (<Placeholder>
                    <Spinner />
                </Placeholder>
            );
        }

        return (<Fragment>
                <div className="wholesome-plugin__header">
                    <div className="wholesome-plugin__container">
                        <div className="wholesome-plugin__title">
                            <h1>{ __( 'Wholesome Plugin Settings', 'wholesome-plugin') } <Icon icon="admin-plugins" /></h1>
                        </div>
                    </div>
                </div>

                <div className="wholesome-plugin__main">
                    <Panel>
                        <PanelBody
                            title={ __( 'Panel Body One', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <SelectControl
                                help={ __( 'An example dropdown field.', 'wholesome-plugin') }
                                label={ __( 'Example Select', 'wholesome-plugin') }
                                onChange={ (exampleSelect) => this.setState( { exampleSelect }) }
                                options={ [
                                    {
                                        label: __( 'Please Select...', 'wholesome-plugin' ),
                                        value: '',
                                    },
                                    {
                                        label: __( 'Option 1', 'wholesome-plugin' ),
                                        value: 'option-1',
                                    },
                                    {
                                        label: __( 'Option 2', 'wholesome-plugin' ),
                                        value: 'option-2',
                                    },
                                ] }
                                value={ exampleSelect }
                            />
                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Two', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <TextControl
                                help={ __( 'This is an example text field.', 'wholesome-plugin') }
                                label={ __( 'Example Text', 'wholesome-plugin') }
                                onChange={ (exampleText) => this.setState( { exampleText }) }
                                value={ exampleText }
                            />

                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Three', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <PanelRow>
                                <TextControl
                                    help={ __( 'Use PanelRow to place controls inline.', 'wholesome-plugin') }
                                    label={ __( 'Example Text 2', 'wholesome-plugin') }
                                    onChange={ (exampleText2) => this.setState( { exampleText2 }) }
                                    value={ exampleText2 }
                                />
                                <TextControl
                                    help={ __( 'This control is inline.', 'wholesome-plugin') }
                                    label={ __( 'Example Text 3', 'wholesome-plugin') }
                                    onChange={ (exampleText3) => this.setState( { exampleText3 }) }
                                    value={ exampleText3 }
                                />
                            </PanelRow>
                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Four', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <ToggleControl
                                checked={ exampleToggle }
                                help={ __( 'An example toggle.', 'wholesome-plugin') }
                                label={ __( 'Example Toggle', 'wholesome-plugin') }
                                onChange={ (exampleToggle) => this.setState( { exampleToggle }) }
                            />
                        </PanelBody>
                        <Button
                            isPrimary
                            isLarge
                            onClick={ () => {}}
                        >
                            { __( 'Save', 'wholesome-plugin') }
                        </Button>
                    </Panel>
                </div>
            </Fragment>) }
}

document.addEventListener( 'DOMContentLoaded', () => {
    const htmlOutput = document.getElementById( 'wholesome-plugin-settings' );

    if (htmlOutput) {
        render(
            <App />,
            htmlOutput
        );
    }
});

Além da remoção do subscribein componentDidMountque usamos anteriormente para salvar nesse guia e da adição do botão, o código é praticamente copiar e colar.

Se tudo estiver bem, nossa página de configurações agora deve se parecer um pouco com isso:

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)Renderizando os campos de configuração

Não se preocupe, vamos limpar os estilos na seção 4 deste guia.

Lidar com o Salvar

No onClickmanipulador do <button>componente adicione o seguinte código:

<Button
  isPrimary
  isLarge
  onClick={ () => {
    const {
      exampleSelect,
      exampleText,
      exampleText2,
      exampleText3,
      exampleToggle,
    } = this.state;

    const settings = new api.models.Settings( {
      [ 'wholesomecode_wholesome_plugin_example_select' ]: exampleSelect,
      [ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,
      [ 'wholesomecode_wholesome_plugin_example_text_2' ]: exampleText2,
      [ 'wholesomecode_wholesome_plugin_example_text_3' ]: exampleText3,
      [ 'wholesomecode_wholesome_plugin_example_toggle' ]: exampleToggle? 'true': '',
    } );
    settings.save();
  }}
  >
  { __( 'Save', 'wholesome-plugin') }
</Button>

Isso salvará nossas opções e configurações quando o botão for clicado. No entanto, não há indicação de que as opções foram salvas por padrão.

Criar a notificação

Para dar ao nosso usuário algum feedback de que as opções e configurações foram salvas, vamos implementar uma notificação de ‘snackbar’. Esta é a mesma notificação usada na tela principal do Editor de Post que o editor de blocos usa quando o post foi salvo.

Para adicionar isso, precisamos portar um componente principal do Gutenberg em nossa compilação, pois a lista de notificações não está disponível usando as instruções de importação usuais.

Precisamos adicionar o seguinte código no arquivo:

import { SnackbarList } from '@wordpress/components';

import {
    dispatch,
    useDispatch,
    useSelect,
} from '@wordpress/data';

import { store as noticesStore } from '@wordpress/notices';

const Notices = () => {
    const notices = useSelect( (select) =>
            select( noticesStore) .getNotices()
                .filter( (notice) => notice.type === 'snackbar' ),
        []
    );
    const { removeNotice } = useDispatch( noticesStore );
    return (<SnackbarList
            className="edit-site-notices"
            notices={ notices }
            onRemove={ removeNotice }
        />
    );
};

Em seguida, na renderização principal do <App>componente, adicione o seguinte antes do fechamento </Fragment>:

<div className="wholesome-plugin__notices">
  <Notices/>
</div>

Por fim, adicione o seguinte ao onClickmanipulador do botão:

dispatch('core/notices').createNotice(
  'success',
  __( 'Settings Saved', 'wholesome-plugin' ),
  {
    type: 'snackbar',
    isDismissible: true,
  }
);

Isso criará um pequeno pop-up ‘snackbar’ sempre que as configurações forem salvas.

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)Notificação da lanchonete em ação

Eu sei, eu sei, ainda precisamos corrigir esses estilos.

O /src/admin.jsarquivo completo

Para referência, aqui está o /src/admin.jscódigo completo do arquivo:

import './admin.scss';

import api from '@wordpress/api';

import {
    Button,
    Icon,
    Panel,
    PanelBody,
    PanelRow,
    Placeholder,
    SelectControl,
    SnackbarList,
    Spinner,
    TextControl,
    ToggleControl,
} from '@wordpress/components';

import {
    dispatch,
    useDispatch,
    useSelect,
} from '@wordpress/data';

import {
    Fragment,
    render,
    Component,
} from '@wordpress/element';

import { __ } from '@wordpress/i18n';

import { store as noticesStore } from '@wordpress/notices';

const Notices = () => {
    const notices = useSelect( (select) =>
            select( noticesStore) .getNotices()
                .filter( (notice) => notice.type === 'snackbar' ),
        []
    );
    const { removeNotice } = useDispatch( noticesStore );
    return (<SnackbarList
            className="edit-site-notices"
            notices={ notices }
            onRemove={ removeNotice }
        />
    );
};

class App extends Component {
    constructor() {
        super( ...arguments );

        this.state = {
            exampleSelect: '',
            exampleText: '',
            exampleText2: '',
            exampleText3: '',
            exampleToggle: false,
            isAPILoaded: false,
        };
    }

    componentDidMount() {

        api.loadPromise.then( () => {
            this.settings = new api.models.Settings();

            const { isAPILoaded } = this.state;

            if (isAPILoaded === false) {
                this.settings.fetch().then( (response) => {
                    this.setState( {
                        exampleSelect: response[ 'wholesomecode_wholesome_plugin_example_select' ],
                        exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],
                        exampleText2: response[ 'wholesomecode_wholesome_plugin_example_text_2' ],
                        exampleText3: response[ 'wholesomecode_wholesome_plugin_example_text_3' ],
                        exampleToggle: Boolean( response[ 'wholesomecode_wholesome_plugin_example_toggle' ] ),
                        isAPILoaded: true,
                    } );
                } );
            }
        } );
    }

    render() {
        const {
            exampleSelect,
            exampleText,
            exampleText2,
            exampleText3,
            exampleToggle,
            isAPILoaded,
        } = this.state;

        if (! isAPILoaded) {
            return (<Placeholder>
                    <Spinner />
                </Placeholder>
            );
        }

        return (<Fragment>
                <div className="wholesome-plugin__header">
                    <div className="wholesome-plugin__container">
                        <div className="wholesome-plugin__title">
                            <h1>{ __( 'Wholesome Plugin Settings', 'wholesome-plugin') } <Icon icon="admin-plugins" /></h1>
                        </div>
                    </div>
                </div>

                <div className="wholesome-plugin__main">
                    <Panel>
                        <PanelBody
                            title={ __( 'Panel Body One', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <SelectControl
                                help={ __( 'An example dropdown field.', 'wholesome-plugin') }
                                label={ __( 'Example Select', 'wholesome-plugin') }
                                onChange={ (exampleSelect) => this.setState( { exampleSelect }) }
                                options={ [
                                    {
                                        label: __( 'Please Select...', 'wholesome-plugin' ),
                                        value: '',
                                    },
                                    {
                                        label: __( 'Option 1', 'wholesome-plugin' ),
                                        value: 'option-1',
                                    },
                                    {
                                        label: __( 'Option 2', 'wholesome-plugin' ),
                                        value: 'option-2',
                                    },
                                ] }
                                value={ exampleSelect }
                            />
                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Two', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <TextControl
                                help={ __( 'This is an example text field.', 'wholesome-plugin') }
                                label={ __( 'Example Text', 'wholesome-plugin') }
                                onChange={ (exampleText) => this.setState( { exampleText }) }
                                value={ exampleText }
                            />

                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Three', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <PanelRow>
                                <TextControl
                                    help={ __( 'Use PanelRow to place controls inline.', 'wholesome-plugin') }
                                    label={ __( 'Example Text 2', 'wholesome-plugin') }
                                    onChange={ (exampleText2) => this.setState( { exampleText2 }) }
                                    value={ exampleText2 }
                                />
                                <TextControl
                                    help={ __( 'This control is inline.', 'wholesome-plugin') }
                                    label={ __( 'Example Text 3', 'wholesome-plugin') }
                                    onChange={ (exampleText3) => this.setState( { exampleText3 }) }
                                    value={ exampleText3 }
                                />
                            </PanelRow>
                        </PanelBody>
                        <PanelBody
                            title={ __( 'Panel Body Four', 'wholesome-plugin') }
                            icon="admin-plugins"
                        >
                            <ToggleControl
                                checked={ exampleToggle }
                                help={ __( 'An example toggle.', 'wholesome-plugin') }
                                label={ __( 'Example Toggle', 'wholesome-plugin') }
                                onChange={ (exampleToggle) => this.setState( { exampleToggle }) }
                            />
                        </PanelBody>
                        <Button
                            isPrimary
                            isLarge
                            onClick={ () => {
                                const {
                                    exampleSelect,
                                    exampleText,
                                    exampleText2,
                                    exampleText3,
                                    exampleToggle,
                                } = this.state;

                                const settings = new api.models.Settings( {
                                    [ 'wholesomecode_wholesome_plugin_example_select' ]: exampleSelect,
                                    [ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,
                                    [ 'wholesomecode_wholesome_plugin_example_text_2' ]: exampleText2,
                                    [ 'wholesomecode_wholesome_plugin_example_text_3' ]: exampleText3,
                                    [ 'wholesomecode_wholesome_plugin_example_toggle' ]: exampleToggle? 'true': '',
                                } );
                                settings.save();

                                dispatch('core/notices').createNotice(
                                    'success',
                                    __( 'Settings Saved', 'wholesome-plugin' ),
                                    {
                                        type: 'snackbar',
                                        isDismissible: true,
                                    }
                                );
                            }}
                        >
                            { __( 'Save', 'wholesome-plugin') }
                        </Button>
                    </Panel>
                </div>

                <div className="wholesome-plugin__notices">
                    <Notices/>
                </div>

            </Fragment>) }
}

document.addEventListener( 'DOMContentLoaded', () => {
    const htmlOutput = document.getElementById( 'wholesome-plugin-settings' );

    if (htmlOutput) {
        render(
            <App />,
            htmlOutput
        );
    }
});

Adicione o SCSS

Hora de corrigir esses estilos. Basta adicionar o seguinte no /src/admin.scssarquivo (que você teria criado no guia Adicionar Pontos de Entrada ao Criar Script de Bloco .

#wholesome-plugin-settings {

    .components-placeholder {
        background: #f1f1f1;
    }

    .wholesome-plugin__header {
        background-color: #ffffff;
        box-shadow: 0 1px 0 rgba(213, 213, 213, .5), 0 1px 2px #eeeeee;
        margin-left: -2em;
        padding: 20px 10px;

        .wholesome-plugin__container {
            margin: 0 auto;
            max-width: 750px;

            .wholesome-plugin__title {
                align-items: center;
                display: flex;
                justify-content: center;

                .dashicon {
                    color: #757575;
                }
            }
        }
    }

    .wholesome-plugin__main {
        margin-left: auto;
        margin-right: auto;
        max-width: 750px;

        .components-panel {
            background: none;
            border: none;
        }

        .components-panel__body {
            background: #ffffff;
            border: 1px solid #e2e4e7;
            margin: 1rem 0;
        }
    }

    .components-base-control__help {
        margin-top: .5rem;
    }

    .components-panel__row {
        > div {
            flex-grow: 1;
            margin-right: 1rem;

            &:last-of-type {
                margin-right: 0;
            }
        }
    }

    .wholesome-plugin__notices {
        .components-snackbar {
            bottom: .5rem;
            position: fixed;
        }
    }
}

Visualizando a página de configurações

Aqui está o resultado final:

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)A página de configurações

Alguns plugins têm um link de ‘configurações’ na página de plugins assim:

Crie uma página de configurações usando os componentes do WordPress Block Editor (Gutenberg)Link de configurações no painel da página de configurações do plug-in

Para conseguir isso, adicione o seguinte bloco de código à raiz do seu arquivo de plug-in (neste caso wholesome-plugin.php):

function wholesomecode_wholesome_plugin_settings_link( $links ): array {
    $label = esc_html__( 'Settings', 'wholesome-plugin' );
    $slug  = 'wholesome_plugin_settings';

    array_unshift( $links, "<a href='options-general.php?page=$slug'>$label</a>" );

    return $links;
}
add_action( 'plugin_action_links_'. plugin_basename( __FILE__ ), 'wholesomecode_wholesome_plugin_settings_link', 10 );

Fonte de gravação: wholesomecode.ltd

Este site usa cookies para melhorar sua experiência. Presumiremos que você está ok com isso, mas você pode cancelar, se desejar. Aceitar Consulte Mais informação