How to add a Media Manager button to a block editor metabox

on in Featured, WordPress
Last modified on

Remember the old “Add Media” button, right above the TinyMCE classic editor? I need it back.

Some of the functionality I offer in my themes and plugins – eCards, WP Property Drive, Foundry – is the option to attach (not insert) images to a custom post type. Then, in the front-end, I display them in a nice carousel. I held onto the old editor for a long time, but it’s now time to let go and implement the “Add Media” in a metabox.

I’ll call the button “Manage Media“. It allows a user to attach images, delete images, and re-order them. I’ll start with adding a regular metabox to a fictional property post type:

<?php
/**
 * Register custom meta boxes.
 *
 * This function registers a custom meta box for the 'property' post type,
 * which allows users to input property details.
 *
 */
function add_meta_boxes() {
    add_meta_box( 'my_meta_box', 'Property Details', 'property_metabox_callback', [ 'property' ], 'normal', 'high' );
}

// Hook the 'add_meta_boxes' function to the WordPress action.
add_action( 'add_meta_boxes', 'add_meta_boxes' );
<?php
/**
 * Callback function for the 'my_meta_box' custom meta box.
 *
 * This function is responsible for rendering the content of the custom meta box.
 * It displays a "Manage Media" button and includes a nonce field for security.
 *
 * @param WP_Post $post The current post object.
 *
 */
function property_metabox_callback( $post ) {
    // Add a nonce field for security.
    wp_nonce_field( 'property', 'property_nonce' );

    // Get the post ID.
    $post_id = $post->ID;

    // Output the HTML content for the meta box.
    ?>
    <p>
        <a href="#" class="my-manage-media-button button button-secondary">Manage Media</a>
    </p>
    <?php
}

As there is no saving option, I don’t need to add an action for saving.

Next, I need to add the JavaScript functionality, and I opted for vanilla JavaScript (no jQuery dependency) and the wp.media.controller.Library library, which is a state for choosing an attachment or group of attachments from the media library:

/**
 * Add event listeners for managing media in the WordPress admin area.
 *
 * This code adds event listeners to handle media management in the WordPress admin area.
 * Specifically, it opens the media manager when the "Manage Media" button is clicked.
 *
 */
document.addEventListener('DOMContentLoaded', function () {
    // Find the "Manage Media" button.
    const uploadButton = document.querySelector('.my-manage-media-button');

    // Check if the button exists.
    if (uploadButton) {
        // Add a click event listener to the button.
        uploadButton.addEventListener('click', function (e) {
            e.preventDefault();

            // Create a WordPress media manager instance.
            const cpUploader = wp.media({
                button: {
                    text: 'Close'
                },
                states: [
                    new wp.media.controller.Library({
                        title: 'Manage media (upload, delete, reorder)',
                        filterable: 'all',
                        sortable: true,
                        multiple: true,
                        selectedImageId: 0,
                        library: wp.media.query({
                            type: 'image',
                        })
                    })
                ]
            });

            // Handle the "select" event when media is selected.
            cpUploader.on('select', function () {
                // Get the selected attachment.
                const attachment = cpUploader.state().get('selection').first().toJSON();
                // No need to handle the selected attachment here, but you can add code as needed.
            });

            // Open the media manager.
            cpUploader.open();
        });
    }
});

This JavaScript file is enqueued in the Dashboard only, and optionally, if the post type matches what I need:

<?php
/**
 * Enqueue scripts and styles for the admin area.
 *
 * This function enqueues the necessary scripts and styles for the admin area,
 * specifically for the 'property' post type. It checks if the 'wp_enqueue_media'
 * action has been executed and enqueues media scripts if not. It also enqueues a
 * custom JavaScript file for managing media.
 *

 */
function my_admin_enqueue_scripts() {
    // Check if 'wp_enqueue_media' action has been executed and the post type is 'property'.
    if ( ! did_action( 'wp_enqueue_media' ) && (string) get_post_type() === 'property' ) {
        wp_enqueue_media();
    }

    // Check if the post type is 'property' and enqueue the custom JavaScript file.
    if ( (string) get_post_type() === 'property' ) {
        wp_enqueue_script( 'manage-media', plugins_url( 'assets/js/admin-media.js', __FILE__ ), [], '1.0.0', true );
    }
}

// Hook the 'my_admin_enqueue_scripts' function to the WordPress action.
add_action( 'admin_enqueue_scripts', 'my_admin_enqueue_scripts' );

The resulting media window will not allow for image insertion, only for uploading, deleting, and re-ordering (note the greyed-out “Close” button):

Photo by Roman Kraft on Unsplash

Related posts