You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Gutenberg富文本编辑器实现类链接弹窗的可编辑脚注按钮

Fixing the Footnote Popup Editor for WordPress Rich Text Format

Let's work through this issue together. The main gap in your current code is that it only toggles the format with a static data-note value, but doesn't include the modal interface needed to edit that attribute dynamically—just like how the default link button works. Here's how to modify your code to add that functionality:

Step 1: Import Required WordPress Components

First, we need to bring in additional components to handle modals, input fields, and state management:

import { Fragment, useState } from '@wordpress/element'; 
import { RichTextToolbarButton, RichTextShortcut } from '@wordpress/block-editor'; 
import { toggleFormat, registerFormatType, getActiveFormat } from '@wordpress/rich-text'; 
import { Modal, TextControl, Button } from '@wordpress/components';

Step 2: Update the Edit Function with Modal Logic

We'll add state to manage the modal's visibility and the current footnote text. When the toolbar button is clicked:

  • If the format is already active, we'll pull the existing data-note value and open the modal to edit it.
  • If it's not active, we'll open an empty modal to let the user input a new footnote.

Here's the revised footnote object:

const name = `custom/eos-footnote`; 
export const footnote = { 
    name, 
    title: 'Footnote', 
    tagName: 'span', 
    className: 'eos-footnote', 
    attributes: { 
        'data-note': 'data-note', // Map the attribute correctly for rich text handling
    }, 
    edit( { isActive, value, onChange } ) { 
        const [ isModalOpen, setIsModalOpen ] = useState( false );
        const [ currentNote, setCurrentNote ] = useState( '' );

        // Fetch the active format to get existing footnote text
        const activeFormat = getActiveFormat( value, name );

        const handleOpenModal = () => {
            // Pre-fill input if editing an existing footnote
            if ( activeFormat ) {
                setCurrentNote( activeFormat.attributes[ 'data-note' ] || '' );
            } else {
                setCurrentNote( '' );
            }
            setIsModalOpen( true );
        };

        const handleSaveNote = () => {
            let updatedValue;
            if ( activeFormat ) {
                // Update existing format with new note
                updatedValue = toggleFormat( value, {
                    type: name,
                    attributes: {
                        'data-note': currentNote,
                    },
                } );
            } else {
                // Apply new format with the entered note
                updatedValue = toggleFormat( value, {
                    type: name,
                    attributes: {
                        'data-note': currentNote,
                    },
                } );
            }
            onChange( updatedValue );
            setIsModalOpen( false );
        };

        const handleCancel = () => {
            setIsModalOpen( false );
            setCurrentNote( '' );
        };

        return ( 
            <Fragment> 
                <RichTextShortcut 
                    type="primary" 
                    character="n" 
                    onUse={ handleOpenModal } 
                /> 
                <RichTextToolbarButton 
                    icon="admin-post" 
                    title={ 'Footnote' } 
                    onClick={ handleOpenModal } 
                    isActive={ isActive } 
                    shortcutType="primary" 
                    shortcutCharacter="n" 
                />

                {/* Footnote Edit Modal */}
                { isModalOpen && (
                    <Modal
                        title={ activeFormat ? 'Edit Footnote' : 'Add Footnote' }
                        onRequestClose={ handleCancel }
                        className="eos-footnote-modal"
                    >
                        <TextControl
                            label="Footnote Text"
                            value={ currentNote }
                            onChange={ setCurrentNote }
                            placeholder="Type your footnote here"
                            autoFocus
                        />
                        <div style={ { marginTop: '16px', display: 'flex', gap: '8px', justifyContent: 'flex-end' } }>
                            <Button variant="secondary" onClick={ handleCancel }>
                                Cancel
                            </Button>
                            <Button variant="primary" onClick={ handleSaveNote } disabled={ !currentNote.trim() }>
                                { activeFormat ? 'Update' : 'Add' }
                            </Button>
                        </div>
                    </Modal>
                ) }
            </Fragment> 
        ); 
    }, 
}; 

Step 3: Keep the Format Registration Function

Your existing registration code works perfectly, so we'll retain it:

function registerFormats () { 
    [ footnote, ].forEach( ( { name, ...settings } ) => registerFormatType( name, settings ) ); 
}; 
registerFormats();

Key Improvements Explained:

  • State Management: We use useState to track the modal's open/closed state and the current footnote text.
  • Active Format Detection: getActiveFormat fetches the existing footnote format (if any) to pre-fill the input with saved text.
  • Modal Interface: The Modal component from @wordpress/components creates the popup, with a TextControl for editing and buttons to save/cancel.
  • Dynamic Format Handling: When saving, we either update an existing footnote or apply a new one based on whether the format was already active.

This implementation will behave exactly like the default link button: clicking the toolbar button (or using Cmd/Ctrl + N) opens a modal to enter or edit footnote text, which is then stored in the data-note attribute of the <span class="eos-footnote"> element.

内容的提问来源于stack exchange,提问作者Rodolfo Estima Rodrigues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 23:07:33