How to Extend the Editor Preview Dropdown with PluginPreviewMenuItem

WordPress 6.7 just introduced the PluginPreviewMenuItem component, and honestly, it’s about time. For years, if we wanted to show a user how their post might look on a social feed or an email newsletter, we had to hack together custom sidebars or modal triggers that lived in awkward places. Now, we have a proper extension point in the Preview dropdown.

In my 14+ years of wrestling with the WordPress editor, I’ve seen plenty of “half-baked” APIs. However, this one follows the established Slot/Fill pattern used by components like PluginMoreMenuItem, making it surprisingly predictable to implement. If you’ve been looking for a way to build a real-time Social Card Preview that reflects unsaved edits, this is the tool for the job.

Why PluginPreviewMenuItem Matters for Custom Workflows

Before this update, adding a custom preview meant deviating from the native user experience. Consequently, developers often bloated the “More Tools” menu or created persistent sidebars that distracted authors. By using PluginPreviewMenuItem, you are placing your tool exactly where the user expects it: under the “Preview” button.

Furthermore, since this runs within the block editor’s React environment, you can tap into the useSelect hook. This allows your preview to be truly reactive. For instance, as an author types a new title, your preview modal can update instantly before they even hit “Save Draft.”

The PHP Side: Bootstrapping the Assets

As with any Gutenberg extension, we start by enqueuing our scripts. I always recommend using the .asset.php file generated by @wordpress/scripts to handle dependencies automatically. This prevents the “white screen of death” caused by missing core scripts.

<?php
/**
 * Enqueue editor assets for the social preview plugin.
 */
function bbioon_enqueue_preview_extension() {
    $asset_file = plugin_dir_path( __FILE__ ) . 'build/index.asset.php';

    if ( ! file_exists( $asset_file ) ) {
        return;
    }

    $asset = include $asset_file;

    wp_enqueue_script(
        'bbioon-social-preview',
        plugin_dir_url( __FILE__ ) . 'build/index.js',
        $asset['dependencies'],
        $asset['version'],
        true
    );
}
add_action( 'enqueue_block_editor_assets', 'bbioon_enqueue_preview_extension' );

The JavaScript Side: Registering the Menu Item

The core logic happens in your src/index.js. We use registerPlugin from the @wordpress/plugins package to inject our component into the Preview Slot.

import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginPreviewMenuItem } from '@wordpress/editor';
import { useState } from '@wordpress/element';
import SocialPreviewModal from './components/SocialPreviewModal';

const SocialPreviewItem = () => {
    const [ isOpen, setIsOpen ] = useState( false );

    return (
        <>
            <PluginPreviewMenuItem
                onClick={ () => setIsOpen( true ) }
            >
                { __( 'Social Card Preview', 'bbioon' ) }
            </PluginPreviewMenuItem>
            { isOpen && (
                <SocialPreviewModal 
                    onClose={ () => setIsOpen( false ) } 
                />
            ) }
        </>
    );
};

registerPlugin( 'bbioon-social-preview', {
    render: SocialPreviewItem,
} );

Reactive Data Fetching with useSelect

The “magic” happens when you pull data from the core/editor store. Unlike a standard frontend preview that relies on the database, getEditedPostAttribute looks at the current state of the editor. This is crucial for authors who want to see how their featured image looks before committing the change.

If you’ve struggled with complex UI components in the past, you might find my guide on choosing selection components helpful when building out the rest of your plugin interface.

Fetching Unsaved Post Data

import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';

const { title, excerpt } = useSelect( ( select ) => {
    const { getEditedPostAttribute } = select( editorStore );
    return {
        title: getEditedPostAttribute( 'title' ),
        excerpt: getEditedPostAttribute( 'excerpt' ),
    };
}, [] );

I’ve used similar patterns when simplifying typography management in custom themes. The key is to keep your selectors lightweight to avoid performance bottlenecks in the editor.

Look, if this PluginPreviewMenuItem stuff is eating up your dev hours, let me handle it. I’ve been wrestling with WordPress since the 4.x days.

A More Native Editor Experience

Specifically, the addition of PluginPreviewMenuItem represents WordPress moving toward a more mature, modular architecture. It allows us to build sophisticated tools—like accessibility checkers or SEO simulators—that feel like they belong in Core. You can find a complete reference implementation in this official example repository.

Therefore, stop using hacky workarounds. Start using the official Slots. It will make your code more maintainable and your clients much happier when the next major WordPress update rolls around.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.

Leave a Comment