DEV Community

Cover image for How to Add Custom Preview Devices to WordPress: Customizer and Block Editor
victorstackAI
victorstackAI

Posted on • Originally published at victorstack-ai.github.io

How to Add Custom Preview Devices to WordPress: Customizer and Block Editor

WordPress offers two distinct preview systems: the Customizer's device preview and the Block Editor's "Preview in new tab" dropdown. Both are extensible, but they require completely different approaches. I dug into both.

â„šī¸ Info: Two Separate APIs

The term "editor preview" is ambiguous in WordPress. The Customizer uses PHP hooks. The Block Editor uses React components. Do not confuse them.

Extension approach comparison

Feature Customizer Preview Block Editor Preview
Extension method PHP filter + action React component (Slot/Fill)
Build tools needed None @wordpress/scripts required
Location Appearance > Customize Post/page editor dropdown
What you add Device sizes with dimensions Menu items with links or actions
Key hook/component customize_previewable_devices PluginPreviewMenuItem

Part 1: Customizer device preview (PHP)

The WordPress Customizer shows device preview buttons for Desktop, Tablet, and Mobile. I can add custom device sizes using PHP hooks.

Architecture

graph TD
    A[WordPress Customizer] -- Loads --> B(Device Preview Buttons);
    B -- User Click --> C{Change Preview?};
    C -- Yes --> D[Apply CSS for Selected Device];

    subgraph Custom Code
        E[functions.php] -- Registers --> F(customize_previewable_devices filter);
        F -- Modifies --> B;
        E -- Hooks into --> G(customize_controls_print_styles action);
        G -- Injects CSS --> D;
    end
Enter fullscreen mode Exit fullscreen mode

1. Register your custom devices

Add this to your theme's functions.php. This hooks into customize_previewable_devices to add "Laptop" and "Large Mobile" options.

```php title="functions.php" showLineNumbers
<?php
/**

  • Add custom device sizes to the WordPress Customizer. *
  • @param array $devices Existing previewable devices.
  • @return array Modified array of previewable devices.
    */
    function my_custom_preview_devices( $devices ) {
    // highlight-start
    $devices['laptop'] = array(
    'label' => __( 'Laptop', 'your-text-domain' ),
    'width' => 1280,
    'height' => 800,
    );

    $devices['large_mobile'] = array(
    'label' => __( 'Large Mobile', 'your-text-domain' ),
    'width' => 414,
    'height' => 896,
    );
    // highlight-end

    return $devices;
    }
    add_filter( 'customize_previewable_devices', 'my_custom_preview_devices' );
    ?>

    
    

2. Add CSS for preview dimensions

Register the CSS that resizes the preview pane for your custom devices.

```php title="functions.php" showLineNumbers
<?php
/**

  • Enqueue custom styles for the WordPress Customizer device previews.
    */
    function my_custom_preview_styles() {
    ?>
    <style type="text/css">
    .wp-customizer .preview-laptop .wp-full-overlay-main {
    width: 1280px;
    height: 800px;
    margin-left: -640px;
    margin-top: -400px;
    left: 50%;
    top: 50%;
    }

    .wp-customizer .preview-large_mobile .wp-full-overlay-main {
        width: 414px;
        height: 896px;
        margin-left: -207px;
        margin-top: -448px;
        left: 50%;
        top: 50%;
    }
    


    <?php
    }
    add_action( 'customize_controls_print_styles', 'my_custom_preview_styles' );
    ?>

    
    

Part 2: Block Editor preview dropdown (React)

The Block Editor's "Preview in new tab" dropdown is a completely different system. You extend it with the PluginPreviewMenuItem React component from @wordpress/editor, using the editor's Slot/Fill pattern.

Architecture

graph TD
    A[Editor Loads] --> B{enqueue_block_editor_assets};
    B --> C{wp_enqueue_script};
    C --> D[Load build/editor.js];
    D --> E[JS runs];
    E --> F{registerPlugin};
    F --> G[Renders MyCustomPreviewItems Component];
    G --> H{PluginPreviewMenuItem};
    H --> I[Adds 'Preview in Dark Mode' to Dropdown];
    H --> J[Adds 'Social Card Preview' to Dropdown];
Enter fullscreen mode Exit fullscreen mode

1. Enqueue the editor script

Tell WordPress to load your script on the editor screen:

```php title="functions.php" showLineNumbers
<?php
function my_theme_enqueue_editor_scripts() {
$asset_file_path = get_theme_file_path('build/editor.asset.php');

if (file_exists($asset_file_path)) {
    $asset_file = include($asset_file_path);

    wp_enqueue_script(
        'my-theme-editor-extensions',
        get_theme_file_uri('build/editor.js'),
        $asset_file['dependencies'],
        $asset_file['version'],
        true
    );
}
Enter fullscreen mode Exit fullscreen mode

}
add_action('enqueue_block_editor_assets', 'my_theme_enqueue_editor_scripts');




> **📝 Note**
>
> This assumes you have a build process (like `@wordpress/scripts`) generating `build/editor.js` and `build/editor.asset.php`.

### 2. Register custom menu items

Create `assets/js/editor.js` with both a direct link and a JavaScript action:



```javascript title="assets/js/editor.js" showLineNumbers
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginPreviewMenuItem } from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';

const MyCustomPreviewItems = () => {
    const { siteUrl, postPreviewLink } = useSelect((select) => {
        const { getSite } = select(coreStore);
        return {
            siteUrl: getSite()?.url,
            postPreviewLink: select('core/editor').getPermalink(),
        };
    }, []);

    const openSocialPreview = () => {
        if (postPreviewLink) {
            window.open(`${postPreviewLink}&preview_mode=social`, '_blank');
        }
    };

    return (
        <>
            {/* Direct link to Dark Mode Preview */}
            // highlight-start
            <PluginPreviewMenuItem
                href={`${postPreviewLink}&theme_mode=dark`}
                target="_blank"
            >
                {__('Preview in Dark Mode', 'my-theme')}
            </PluginPreviewMenuItem>
            // highlight-end

            {/* Custom onClick action */}
            <PluginPreviewMenuItem onClick={openSocialPreview}>
                {__('Social Card Preview', 'my-theme')}
            </PluginPreviewMenuItem>
        </>
    );
};

registerPlugin('my-theme-custom-preview-items', {
    render: MyCustomPreviewItems,
});
Enter fullscreen mode Exit fullscreen mode

PluginPreviewMenuItem props reference

Prop Type Description
href string URL to open in a new tab
target string Link target (typically _blank)
onClick function Custom click handler
children ReactNode Menu item label text

You can mix href links and onClick handlers across multiple PluginPreviewMenuItem components.

Migration checklist

  • [ ] Identify which preview system to extend (Customizer vs. Block Editor)
  • [ ] For Customizer: add customize_previewable_devices filter
  • [ ] For Customizer: add customize_controls_print_styles CSS
  • [ ] For Block Editor: set up @wordpress/scripts build process
  • [ ] For Block Editor: create PluginPreviewMenuItem component
  • [ ] For Block Editor: enqueue via enqueue_block_editor_assets
  • [x] Test in WordPress 7.0 iframed editor context

💡 Tip: WP 7.0 Consideration

With WordPress 7.0's always-iframed editor, PluginPreviewMenuItem components work correctly because they operate at the plugin slot level, not inside the editor canvas iframe. No additional migration needed.

Why this matters for Drupal and WordPress

WordPress theme developers and agencies building client sites need custom preview options for responsive QA and social card validation. The Customizer device hook is especially useful for WordPress shops that must demo exact device widths to clients. The Block Editor Slot/Fill pattern for PluginPreviewMenuItem also shows the extensibility model that Drupal's CKEditor 5 and Layout Builder teams are watching as they design similar plugin-slot APIs for Drupal's editing experience.

What I learned

  • The term "editor preview" is ambiguous in WordPress. The Customizer and Block Editor have completely separate extension APIs.
  • Customizer: PHP hooks (customize_previewable_devices filter + customize_controls_print_styles action). Simple, no build tools needed.
  • Block Editor: React components (PluginPreviewMenuItem via Slot/Fill). Requires @wordpress/scripts and a JavaScript build process.
  • useSelect from @wordpress/data is key for creating dynamic, context-aware preview links that respond to the current post's state.

References


Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.


Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.

Originally published at VictorStack AI — Drupal & WordPress Reference

Top comments (0)