1

I am trying to create an interface that allows users to manage data stored in posts that pertain to them without actually giving them access to the custom post type that is storing that data.

Everything else is working fine, but I want to add a way for them to upload a profile picture from this page which is being presented in a React app. All of the other elements load just fine, like TextControl and SelectControl, etc. However, I am having a hard time getting MediaUpload to activate outside of the block editor.

Is there some way that I can make it so that I can use it in my react app, so that they can upload the profile pic?

Below is some of the code:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import ReactPhoneInput from 'react-phone-input-2'

let { Button, SelectControl, TextControl, ToggleControl } = window.wp.components
let { MediaUpload, RichText } = window.wp.editor

class ClassmateProfile extends Component {
  constructor (props) {
    super(props)
    this.state = {
      pageID: USNA1978.pageID,
      aboutDetails: USNA1978.aboutDetails,
      aboutImage1: USNA1978.aboutImage1,
      aboutImage2: USNA1978.aboutImage2,
      firstName: USNA1978.firstName,
      middleName: USNA1978.middleName,
      lastName: USNA1978.lastName,
      //...
    }
  }

  render () {
    if (this.state.pageID) {
      return (
        <div className='profile-layout'>
          <div className='left-side'>
            <div className='panel panel-default'>
              <div className='panel-heading'>
                <strong>About</strong>
              </div>
              <div className='panel-body'>
                <div className='image-grid'>
                  <div>
                    {(() => {
                      if (this.state.aboutImage1) {
                        return <img alt='Current Photo' src={this.state.aboutImage1} />
                      } else {
                        return <span>Graduation Photo</span>
                      }
                    })()}
                  </div>
                  <div>
                    {(() => {
                      if (this.state.aboutImage2) {
                        return <img alt='Current Photo' src={this.state.aboutImage2} />
                      } else {
                        return <span>Graduation Photo</span>
                      }
                    })()}
                    <MediaUpload
                      value={this.state.aboutImage2}
                      onSelect={media => this.setState({ aboutImage2: media.url })}
                      render={({ open }) => (
                        <Button className='button button-large sidebar-detail-icon-button' onClick={open}>
                          {!this.state.aboutImage2 ? 'Upload/Select Photo' : 'Change Photo'}
                        </Button>
                      )}
                    />
                  </div>
                </div>
                <RichText
                  tag='p'
                  value={this.state.aboutDetails}
                  onChange={value => this.setState({ aboutDetails: value })}
                  placeholder='Click here to add details about this classmate...'
                />
              </div>
            </div>
            <!-- ... -->
          </div>

          <div className='right-side'>
            <div className='panel panel-default'>
              <div className='panel-heading'>
                <strong>Contact Info</strong>
              </div>
              <div className='panel-body'>
                <table className='borderless'>
                  <tr>
                    <th colSpan='2'>Name &amp; Company</th>
                  </tr>
                  <tr>
                    <td>
                      <label htmlFor='firstName'>First Name</label>
                    </td>
                    <td>
                      <TextControl
                        value={this.state.firstName}
                        onChange={value => this.setState({ firstName: value })}
                      />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <label htmlFor='middleName'>Middle Name</label>
                    </td>
                    <td>
                      <TextControl
                        value={this.state.middleName}
                        onChange={value => this.setState({ middleName: value })}
                      />
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <label htmlFor='lastName'>Last Name</label>
                    </td>
                    <td>
                      <TextControl
                        value={this.state.lastName}
                        onChange={value => this.setState({ lastName: value })}
                      />
                    </td>
                  </tr>
                  <!-- ... -->
                </table>
              </div>
            </div>
          </div>
        </div>
      )
    }
  }
}

if (document.getElementById('edit_classmate_profile')) {
  ReactDOM.render(<ClassmateProfile />, document.getElementById('edit_classmate_profile'))
}
1
  • Just taking a chance to ping you about this, even if it's been a while. I'm just learning about using the react components outside the editor myself and the mediauploader shows blank without error.... 👀 Any clues?
    – davidwebca
    Commented Mar 24, 2021 at 12:36

1 Answer 1

1

The answer is actually several steps that took me lots of experimentation, but it comes down to the following code that you need to compile using something like webpack and extract out the libraries, etc:

// MediaUploadFilter.js
import { MediaUpload } from '@wordpress/media-utils'
 
const { addFilter } = window.wp.hooks
const replaceMediaUpload = () => MediaUpload

addFilter(
  'editor.MediaUpload',
  'core/edit-post/components/media-upload/replace-media-upload',
  replaceMediaUpload
)

Essentially this class I have stripped down for you to see is being called during init hook:

<?php
public function __construct()
{
    add_action('admin_menu', [$this, 'setAdminMenus']);
    // ...
}
public function setAdminMenus(): void
{
    $pageMenuObject = add_menu_page(
        'Classmate Profile',
        'Classmate Profile',
        'edit_classmates_profile',
        'classmate-profile',
        [$this->displayHandler, 'displayPage'], // a function loading a view
        'dashicons-admin-users',
        21
    );

    add_action('admin_enqueue_scripts', static function ($hook) use ($pageMenuObject) {
       /**
         * Make sure that we load the scripts specific to the add to release page
         */
        if ($hook === $pageMenuObject) {
            $pageMenuData = ClassmateProfileData::getInstance(); // Grabs data for user
            $allPageData = [];
            if ($pageMenuData) {
                $allPageData = $pageMenuData->getPageData() ?: [];
            }

            static::enqueueLibraryAssets(); // See below abstract function I pasted below

            wp_enqueue_script(
                'plugin-classmate-profile',
                mix_plugin_uri('/assets/js/ClassmateProfile.js'),
                ['plugin-media-upload-filter', 'wp-editor', 'wp-block-editor'],
                PLUGIN_VERSION,
                true
            );
            wp_localize_script(
                'plugin-classmate-profile',
                'ClassmateProfileData',
                $allPageData
            );
        }
    });
}
// This is from the parent abstract class for the class I am calling it in
public static function enqueueLibraryAssets(): void
{
    wp_enqueue_style(
        'plugin-application',
        mix_plugin_uri('assets/css/app.css'),
        ['wp-edit-blocks'],
        PLUGIN_VERSION
    );
    wp_enqueue_media(); // MUST HAVE THIS! Loads the files you need...
    wp_enqueue_script(
        'plugin-library-manifest',
        mix_plugin_uri('assets/js/manifest.js'),
        ['lodash', 'react', 'react-dom', 'wp-components', 'wp-i18n', 'wp-element', 'wp-editor'],
        PLUGIN_VERSION,
        true
    );
    wp_enqueue_script(
        'plugin-library-vendor',
        mix_plugin_uri('assets/js/vendor.js'),
        ['plugin-library-manifest'],
        PLUGIN_VERSION,
        true
    );
    wp_enqueue_script(
        'plugin-media-upload-filter',
        mix_plugin_uri('assets/js/MediaUploadFilter.js'),
        ['plugin-library-manifest', 'plugin-library-vendor'],
        PLUGIN_VERSION,
        true
    );
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.