Title: How to add custom entries to the editor Preview dropdown
Author: Birgit Pauli-Haack
Published: February 19, 2026

---

 * [Showcase](https://wordpress.org/showcase/)
 * [Plugins](https://wordpress.org/plugins/)
 * [Themes](https://wordpress.org/themes/)
 * [Hosting](https://wordpress.org/hosting/)
 * [News](https://wordpress.org/news/)
    - [Learn WordPress](https://learn.wordpress.org/)
    - [Documentation](https://wordpress.org/documentation/)
    - [Education](https://wordpress.org/education/)
    - [Forums](https://wordpress.org/support/forums/)
    - [Developers](https://developer.wordpress.org/)
    - [Blocks](https://wordpress.org/blocks/)
    - [Patterns](https://wordpress.org/patterns/)
    - [Photos](https://wordpress.org/photos/)
    - [Openverse ︎](https://openverse.org/)
    - [WordPress.tv ︎](https://wordpress.tv/)
 *  - [About WordPress](https://wordpress.org/about/)
    - [Make WordPress](https://make.wordpress.org/)
    - [Events](https://events.wordpress.org/)
    - [Five for the Future](https://wordpress.org/five-for-the-future/)
    - [Enterprise](https://wordpress.org/enterprise/)
    - [Gutenberg ︎](https://wordpress.org/gutenberg/)
    - [Job Board ︎](https://jobs.wordpress.net/)
 * [Swag ︎](https://mercantile.wordpress.org/)
 * [Get WordPress](https://wordpress.org/download/)

Search in WordPress.org

 [ Get WordPress ](https://wordpress.org/download/)

[WordPress Developer Blog](https://developer.wordpress.org/news)

How to add custom entries to the editor Preview dropdown

 * [Snippets](https://developer.wordpress.org/news/snippets/)
    - [Blocks](https://developer.wordpress.org/news/category/blocks/)
    - [Concepts](https://developer.wordpress.org/news/category/concepts/)
    - [Common APIs](https://developer.wordpress.org/news/category/common-apis/)
    - [Design](https://developer.wordpress.org/news/category/design/)
    - [Playground](https://developer.wordpress.org/news/category/playground/)
    - [Plugins](https://developer.wordpress.org/news/category/plugins/)
    - [Themes](https://developer.wordpress.org/news/category/themes/)
 *  - [About this site](https://developer.wordpress.org/news/about/)
    - [Updates](https://developer.wordpress.org/news/category/updates/)
    - [How to contribute](https://developer.wordpress.org/news/how-to-contribute/)
    - [Tips and guidelines](https://developer.wordpress.org/news/tips-and-guidelines-for-writers/)
 * [Subscribe](https://developer.wordpress.org/news/subscribe/)
 * [Developer Resources](https://developer.wordpress.org/)

 * [Snippets](https://developer.wordpress.org/news/snippets/)
    - [Blocks](https://developer.wordpress.org/news/category/blocks/)
    - [Concepts](https://developer.wordpress.org/news/category/concepts/)
    - [Common APIs](https://developer.wordpress.org/news/category/common-apis/)
    - [Design](https://developer.wordpress.org/news/category/design/)
    - [Playground](https://developer.wordpress.org/news/category/playground/)
    - [Plugins](https://developer.wordpress.org/news/category/plugins/)
    - [Themes](https://developer.wordpress.org/news/category/themes/)
 *  - [About this site](https://developer.wordpress.org/news/about/)
    - [Updates](https://developer.wordpress.org/news/category/updates/)
    - [How to contribute](https://developer.wordpress.org/news/how-to-contribute/)
    - [Tips and guidelines](https://developer.wordpress.org/news/tips-and-guidelines-for-writers/)
 * [Subscribe](https://developer.wordpress.org/news/subscribe/)
 * [Developer Resources](https://developer.wordpress.org/)

# How to add custom entries to the editor Preview dropdown

By [Birgit Pauli-Haack](https://profiles.wordpress.org/bph/)

February 19, 2026

[Beginners](https://developer.wordpress.org/news/category/beginners/), [Common APIs](https://developer.wordpress.org/news/category/common-apis/),
[Plugins](https://developer.wordpress.org/news/category/plugins/)

[Since WordPress 6.7](https://make.wordpress.org/core/2024/10/18/extending-the-preview-dropdown-menu-in-wordpress-6-7/),
plugin developers can extend the Preview dropdown in the editor with custom menu
items. This is possible through the `[PluginPreviewMenuItem](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-editor/#pluginpreviewmenuitem)`
component from the `@wordpress/editor` package. This article walks through building
a small plugin that adds a “Social Card Preview” option — showing how a post will
look when shared on X.

![Screenshot of a Preview Menu ](https://developer.wordpress.org/news/files/2026/
02/Screenshot-2026-02-18-at-16.20.58.png)

Table of Contents

 1.  [What is PluginPreviewMenuItem?](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#what-is-pluginpreviewmenuitem)
 2.  [Social Card Preview example](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#social-card-preview-example)
 3.  [Plugin setup](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#plugin-setup)
 4.   a. [The PHP bootstrap](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#the-php-bootstrap)
      b. [Build tooling](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#build-tooling)
 5.  [Registering the preview menu item](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#registering-the-preview-menu-item)
 6.  [Building the social card modal](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#building-the-social-card-modal)
 7.  [The Card Preview markup](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#the-card-preview-markup)
 8.  [Styling the card](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#styling-the-card)
 9.  [Testing with WordPress Playground](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#testing-with-wordpress-playground)
 10. [Going further](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/#going-further)

## What is PluginPreviewMenuItem?

The **Preview** dropdown sits in the editor’s top bar and lets users preview their
content in different ways. Before WordPress 6.7, only Core add items there. With`
PluginPreviewMenuItem` component, plugins can register their own entries in that
dropdown. It uses the same [Slot/Fill pattern](https://developer.wordpress.org/block-editor/reference-guides/components/slot-fill/)
that powers other extension points like `PluginMoreMenuItem` or `PluginSidebar`.

The component accepts an `onClick` handler for button behavior or an `href` for 
link behavior. You can also pass an optional `icon` prop. The text you place between
the opening and closing `<PluginPreviewMenuItem>` tags becomes the label shown in
the menu.

## Social Card Preview example

This plugin adds a **Social Card Preview** item to the **Preview** dropdown. When
clicked, it opens a modal that shows a mock preview of how the current post would
appear as an X card. The modal reads the post title, excerpt, and featured image
directly from the editor store, so it always reflects the latest unsaved edits. 
You can take a peek at the [example plugin on GitHub. ](https://github.com/bph/dev-blog-custom-preview)

![Screenshot of Preview displayed in a modal](https://developer.wordpress.org/news/
files/2026/02/Screenshot-2026-02-18-at-13.47.22.png)

## Plugin setup

Following along, you start with the file structure. The plugin needs a main PHP 
file for WordPress to recognize it, a `package.json` for the build tooling, and 
the source files in a `src/` folder.

    ```language-markdown
    custom-preview/
    ├── custom-preview.php
    ├── package.json
    └── src/
        ├── index.js
        ├── social-card-preview.js
        └── style.css
    ```

### The PHP bootstrap

The main plugin file, `custom-preview.php`, registers the script and stylesheet 
on the `enqueue_block_editor_assets` hook. The code uses the asset file that `@wordpress/
scripts` generates during the build — it contains the dependency list and a version
hash so WordPress can handle caching properly. The below code goes after the [PHP plugin header](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/).

    ```php
    function social_card_preview_enqueue_editor_assets() {
    	$asset_file = plugin_dir_path( __FILE__ ) . 'build/index.asset.php';

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

    	$asset = include $asset_file;

    	wp_enqueue_script(
    		'social-card-preview-editor',
    		plugin_dir_url( __FILE__ ) . 'build/index.js',
    		$asset['dependencies'],
    		$asset['version'],
    		true
    	);

    	wp_enqueue_style(
    		'social-card-preview-editor',
    		plugin_dir_url( __FILE__ ) . 'build/style-index.css',
    		array(),
    		$asset['version']
    	);
    }
    add_action( 'enqueue_block_editor_assets', 'social_card_preview_enqueue_editor_assets' );
    ```

This is a common pattern in WordPress block editor plugin development. The `enqueue_block_editor_assets`
hook makes sure [the script and styles only load inside the editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/#editor-scripts-and-styles),
not on the frontend.

### Build tooling

For the JavaScript build, `@wordpress/scripts` handles the tooling. The `package.
json` is minimal:

    ```language-json
    {
    	"name": "social-card-preview",
    	"version": "1.0.0",
    	"scripts": {
    		"build": "wp-scripts build",
    		"start": "wp-scripts start"
    	},
    	"devDependencies": {
    		"@wordpress/scripts": "^30.0.0"
    	}
    }
    ```

Run `npm install` to get the dependencies, then `npm run build` to compile. During
development, `npm run start` watches for changes and rebuilds automatically.

## Registering the preview menu item

The entry point `src/index.js` is where the plugin is registered and the menu item
is added to the Preview dropdown. The idea behind it: render a `PluginPreviewMenuItem`
that, when clicked, opens a modal.

    ```line-numbers
    import { __ } from '@wordpress/i18n';
    import { registerPlugin } from '@wordpress/plugins';
    import { PluginPreviewMenuItem } from '@wordpress/editor';
    import { useState } from '@wordpress/element';

    import SocialCardPreview from './social-card-preview';
    import './style.css';

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

    	return (
    		<>
    			<PluginPreviewMenuItem
    				onClick={ () => setIsOpen( true ) }
    			>
    				{ __( 'Social Card Preview', 'social-card-preview' ) }
    			</PluginPreviewMenuItem>
    			{ isOpen && (
    				<SocialCardPreview
    					onClose={ () => setIsOpen( false ) }
    				/>
    			) }
    		</>
    	);
    };

    registerPlugin( 'social-card-preview', {
    	render: SocialCardPreviewMenuItem,
    } );
    ```

A few things to note here:

 * The code uses `registerPlugin` from `[@wordpress/plugins](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-plugins/)`
   to register the component.
 * The `PluginPreviewMenuItem` works like any other menu item — give it an `onClick`
   and some children for the label.
 * Modal visibility is managed with a basic `useState` toggle.

## Building the social card modal

The `SocialCardPreview` component reads data from the editor store and renders a
mock X card inside a `Modal`.

    ```javascript
    import { __ } from '@wordpress/i18n';
    import { Modal } from '@wordpress/components';
    import { useSelect } from '@wordpress/data';
    import { store as editorStore } from '@wordpress/editor';
    import { store as coreStore } from '@wordpress/core-data';

    const SocialCardPreview = ( { onClose } ) => {
    	const { title, excerpt, imageUrl, siteUrl } = useSelect( ( select ) => {
    		const { getEditedPostAttribute } = select( editorStore );
    		const featuredMediaId = getEditedPostAttribute( 'featured_media' );

    		let featuredImageUrl = '';
    		if ( featuredMediaId ) {
    			const media = select( coreStore ).getMedia( featuredMediaId );
    			featuredImageUrl =
    				media?.media_details?.sizes?.large?.source_url ||
    				media?.source_url ||
    				'';
    		}

    		return {
    			title: getEditedPostAttribute( 'title' ) || '',
    			excerpt: getEditedPostAttribute( 'excerpt' ) || '',
    			imageUrl: featuredImageUrl,
    			siteUrl: select( coreStore ).getSite()?.url || '',
    					};
    	}, [] );

    	const domain = siteUrl ? new URL( siteUrl ).hostname : '';
    	const truncatedExcerpt =
    		excerpt.length > 200
    			? excerpt.substring( 0, 200 ) + '…'
    			: excerpt;

    	return (
    		<Modal title={ __( 'X Preview', 'social-card-preview' ) } 
                           onRequestClose={ onClose } 
                           size="medium">
    			{ /* Card preview markup see below */ }
    		</Modal>
    	);
    };
    ```

Here is a breakdown. The `useSelect` hook pulls the required data from two stores.
From the `editor` store, it retrieves the post title, excerpt, and featured media
ID. From the `core-data` store, it resolves the media ID to an actual image URL 
and fetches the site URL to display the domain name on the card.

For the featured image, the code tries the `large` size first, falling back to the
full `source_url`. The excerpt gets truncated to 200 characters because that is 
roughly what X shows.

Because `useSelect` is reactive, the preview updates in real time as you edit the
post. Change the title, and the card updates immediately — no need to save first.

## The Card Preview markup

The card markup mirrors how X renders link previews. The featured image sits at 
the top, followed by a content area with the domain, title, and truncated excerpt.
The image only renders when a featured image exists, thanks to the conditional `
imageUrl &&` check. 

Each piece of text uses a `<span>` rather than a heading or paragraph because this
is a visual mock — not semantic document content. The class names like `social-card-
preview__title` follow the [BEM (Block Element Modifier)](https://getbem.com/) naming
convention — `social-card-preview` is the block, and `__title`, `__domain`,  `__description`
are elements within it. This keeps the styles scoped and avoids collisions with 
editor styles.

The below text goes between the `<Modal></Modal>` tags in above code example. The
complete `[social-card-preview.js](https://github.com/bph/dev-blog-custom-preview/blob/main/src/social-card-preview.js)`
is also on GitHub:

    ```line-numbers
    <div className="social-card-preview">
        <div className="social-card-preview__card social-card-preview__card--twitter">
    	{ imageUrl && (
    		<img className="social-card-preview__image"
    			src={ imageUrl }
    			alt=""
    		/>
    	) }
          <div className="social-card-preview__content">
    	  <span className="social-card-preview__domain">
    		{ domain }
    	  </span>
              <span className="social-card-preview__title">
    	       { title }
             </span>
             <span className="social-card-preview__description">
    	         { truncatedExcerpt }
             </span>
         </div>
      </div>
    </div>
    ```

## Styling the card

The CSS approximates how X renders link cards and follows the naming decision from
above.

    ```language-css
    .social-card-preview__card {
    	border: 1px solid #dadce0;
    	border-radius: 16px;
    	overflow: hidden;
    }

    .social-card-preview__title {
    	display: -webkit-box;
    	-webkit-line-clamp: 2;
    	-webkit-box-orient: vertical;
    	overflow: hidden;
    }
    ```

The card uses a 16px border radius to match X’s rounded style. The `-webkit-line-
clamp` rules handle text truncation for the title and description.

## Testing with WordPress Playground

You do not need a full WordPress installation to test this. The [Playground CLI](https://wordpress.github.io/wordpress-playground/developers/local-development/wp-playground-cli/)
gives you a disposable WordPress instance in seconds. Make sure you have Node.js
20.18 or later, then from the plugin directory run:

    ```bash
    npm install
    npm run build
    npx @wp-playground/cli@latest server --auto-mount --login
    ```

Playground detects the plugin, automatically mounts it and logs in the admin user.
Open `http://127.0.0.1:9400` in your browser, create or edit a post, and you should
see “Social Card Preview” in the Preview dropdown.

## Going further

The social card example is one way to use `PluginPreviewMenuItem`. The slot opens
up a range of preview experiences that were previously only available to WordPress
core. Here are some other use cases to consider:

 * **Accessibility checker** — open a modal that scans the post content for common
   accessibility issues, such as missing alt text or low-contrast headings, before
   the author hits publish.
 * **Reading level preview** — show a readability score and a simplified version
   of the content, useful for publishers targeting a broad or non-specialist audience.
 * **External preview service** — use the `href` prop instead of `onClick` to send
   the author directly to a third-party staging or QA environment with the post 
   URL pre-filled.
 * **Email newsletter preview** — for plugins that sync posts to an email list, 
   show a rendered preview of how the content will look in an email client, including
   any template wrapping applied by the plugin.

Any time your plugin needs to give authors a way to see or check their content before
publishing, `PluginPreviewMenuItem` is the right place to add it.

_Props to _[@greenshady](https://profiles.wordpress.org/greenshady/)_and _[@juanmaguitar](https://profiles.wordpress.org/juanmaguitar/)
_for reviews._

**Share the post: **

**Categories:** [Beginners](https://developer.wordpress.org/news/category/beginners/),
[Common APIs](https://developer.wordpress.org/news/category/common-apis/), [Plugins](https://developer.wordpress.org/news/category/plugins/)

**Tags:** [Block editor](https://developer.wordpress.org/news/tag/block-editor/),
[Editor Curation](https://developer.wordpress.org/news/tag/editor-curation/)

### Leave a Reply 󠀁[Cancel reply](https://developer.wordpress.org/news/2026/02/how-to-add-custom-entries-to-the-editor-preview-dropdown/?output_format=md#respond)󠁿

Your email address will not be published. Required fields are marked *

Comment *

Name *

Email *

Website

 Save my name, email, and website in this browser for the next time I comment.

 Notify me of follow-up comments by email.

 Notify me of new posts by email.

Δ

## Have an idea for a new post?

### 󠀁[Learn how to contribute](https://developer.wordpress.org/news/how-to-contribute/)󠁿

Share your knowledge with fellow WordPress developers.

Search

### 󠀁[Review tips and guidelines](https://developer.wordpress.org/news/tips-and-guidelines-for-writers/)󠁿

Everything you need to know about writing for the Blog.

## Subscribe to the Blog

  Email Address

 Join 1,771 other subscribers

 * [About](https://wordpress.org/about/)
 * [News](https://wordpress.org/news/)
 * [Hosting](https://wordpress.org/hosting/)
 * [Privacy](https://wordpress.org/about/privacy/)

 * [Showcase](https://wordpress.org/showcase/)
 * [Themes](https://wordpress.org/themes/)
 * [Plugins](https://wordpress.org/plugins/)
 * [Patterns](https://wordpress.org/patterns/)

 * [Learn](https://learn.wordpress.org/)
 * [Documentation](https://wordpress.org/documentation/)
 * [Developers](https://developer.wordpress.org/)
 * [WordPress.tv ](https://wordpress.tv/)

 * [Get Involved](https://make.wordpress.org/)
 * [Events](https://events.wordpress.org/)
 * [Donate ](https://wordpressfoundation.org/donate/)
 * [Swag ](https://mercantile.wordpress.org/)

 * [WordPress.com ](https://wordpress.com/?ref=wporg-footer)
 * [Matt ](https://ma.tt/)
 * [bbPress ](https://bbpress.org/)
 * [BuddyPress ](https://buddypress.org/)

 * [Visit our X (formerly Twitter) account](https://www.x.com/WordPress)
 * [Visit our Bluesky account](https://bsky.app/profile/wordpress.org)
 * [Visit our Mastodon account](https://mastodon.world/@WordPress)
 * [Visit our Threads account](https://www.threads.net/@wordpress)
 * [Visit our Facebook page](https://www.facebook.com/WordPress/)
 * [Visit our Instagram account](https://www.instagram.com/wordpress/)
 * [Visit our LinkedIn account](https://www.linkedin.com/company/wordpress)
 * [Visit our TikTok account](https://www.tiktok.com/@wordpress)
 * [Visit our YouTube channel](https://www.youtube.com/wordpress)
 * [Visit our Tumblr account](https://wordpress.tumblr.com/)

![Code is Poetry](https://s.w.org/style/images/code-is-poetry-for-dark-bg.svg)

 The WordPress® trademark is the intellectual property of the WordPress Foundation.