PHP ROUTE

Custom Block Development Part-7: Image, Audio, Video in Block

This is the seventh part of our custom block development series, in this article we are going to learn about handling media files for blocks. We are going to learn how we can use a custom image for our block icon and also how to use images stored inside the block itself not getting from WordPress media. After that, we will take a look at how we can use Image, Video, and Audio files inside our block. So let’s begin.

This article is the continuation of our previous articles on this topic so if you haven’t read them and don’t have prior knowledge of custom block development then I highly recommend checking our previous article on this topic or check the complete list of all the articles on this topic.

Till now we have learned how we can create our own custom block with some editable text and how we can give users options to style the blocks with toolbar and sidebar. But we haven’t learned about handling media so in this article our prime focus will be handling media, do note that I am not caring about the styling because you already know how to do so, I am not doing anything for styling for our block.

New Custom Block

For using media, I have created a completely new block called “Media Block”. I have already shared with you guys how you can create multiple blocks and register them using PHP so I am not gonna repeated that. If you wanna a refresher on how to do that here’s the link.

I have also coded the basic requirement and created a block and you don’t need an explanation for that as well. So after making the changes and creating the new block our index.php is as shown below.

const { registerBlockType } = wp.blocks;

registerBlockType("wpt/media", {
  title: "Media Block",
  icon: ,
  category: "custom-category",
  descriptio:"A custom Block with Image, Audio, and Video.",
  attributes: {
   
      //attributes

  },

  edit: props => {

    return (
      <div className={props.className}>
         
      </div>
    );
  },
  save: props => {

    return (
      <div className={props.className}>
       
      </div>   
    );
  }
});

Add Custom Icon

One thing you may have noticed in the above example is we haven’t added any dashicon icon for our block that is because now I want to show you guys how you can add your custom image as a block icon. I am going to use an SVG file as an icon, you may use PNG or other formats but I recommend using SVG. The reason to use SVG is its calling capability and smaller size.

Now to add an SVG as an icon first add your SVG into your block folder, you can have a separate folder if you want but I am keeping mine in the src folder for simplicity.

After we need to import that SVG file inside our block, we can do that by following the code I have shared below. We are importing the SVG image as react component and storing it as “Logo” so we can reference it later.

import { ReactComponent as Logo } from "../logo.svg";

After importing the SVG simply where we use dashicon icon name as block icon we need to type “Logo” and our new custom logo will be our block icon. You don’t need to do anything extra WordPress itself handles the color of the icon on the on-click and hover.

Add Image in Block

Now let’s see how we can add an Image in our block and also how to give users options to add their own images from the media library. For adding media from the media library we will be using MediaUploadcomponent. This component exists inside the wp.blockEditorpackage. Check the Media Upload documenation on this repo.

Image as Placeholder

Before adding an image picker let’s just add a simple placeholder image for our block, you can also follow this same step to add any decorative image that you don’t want to let end-user replace.

To add the placeholder first add the image in the block folder locally, then import that image file in our block. This time we won’t gonna import it as ReactComponent but a normal component as placeHolder.

import placeHolder from "../place_holder.png";

Now to use this image as a placeholder we just need to add it in <img>source as we do generally in HTML. We need to do the same thing for editand savefunction. The code will look like the code below:

const { registerBlockType } = wp.blocks;

import placeHolder from "../place_holder.png";

registerBlockType("wpt/media", {
  title: "Media Block",
  icon: { src: Logo },
  category: "custom-category",
  descriptio:"A custom Block with Image, Audio, and Video.",

  edit: props => {

    return (
      <div className = { props.className } >
          <div className = { 'image-container' } >
            <img src = { placeHolder } alt= "logo" />
          </div>
      </div>
    );
  },
  save: props => {

    return (
      <div className = { props.className } >
          <div className = { 'image-container' } >
            <img src = { placeHolder } alt="logo" />
          </div>
      </div>
    );
  }
});

custom block

Image from Media Library

Now let’s see how we can get the image from the media library of WordPress and set that image as our custom block image. So first to get the image from the media library we need MediaUploadcomponent, so let’s import it from the wp.blockEditorpackage first at top of our block script.

const { MediaUpload } = wp.blockEditor;

Now to trigger the media library we will use a separate button IconButtonthat exists in the wp.componentspackage. So import that as well.

const { IconButton } = wp.components;

Now next thing is to create the attributes for our image element. We call our image element attribute blockImageand set it to type to string, we also add sourceas an attribute and set attributeto src. We will also set the defaultto placeholder we have added before.

After that one important thing we need is selectorproperty because without it attribute cannot determine where to place the src. In selector, you need to parse the element which you want to parse, and to be precise just like the CSS selector we will use class name and element name combo to point to the exact element. To pinpoint the exact location first the element need to be added the editand savefunction so you should set it later. We already know how our structure looks so we are going to do it now.

selector: ".image-container img",

With that our attribute for the image is ready and the complete attribute code will be as shown code below.

attributes: {
  blockImage: {
    type: "string",
    source: "attribute",
    attribute: "src",
    selector: ".image-container img",
    default: placeHolder
  },
},

Now let’s first add the component inside our editfunction. First, we will create a container <div> </div>and inside that container div we will create another container div for the image, we are doing this so we can add other containers later for video and audio.

Now in the image container first we need to the <img> </img>tag and set its src to the blockImageattribute we have created above. But now instead of directly referencing attributes as props.attributes.blockImagewe will declare constant inside our edit function before the return statement and in that constant, we will reference the attribute and call it later in our code for cleaner and readable code.

const {
  attributes: { blockImage },
} = props;

After declaring an attribute as a variable we can reference it without using props.

<img src={blockImage} alt="logo" />

Now we will use the actual MediaUploadcomponent to open Media Libray to let the user choose an image for the block. So first we will add the <MediaUpload> <MediaUpload>component and for the MediaUploadwe can pass allowedTypesto only allow certain media types, we can also choose specific file extensions if we want if we pass an array of extensions but for our need, we will simply set it to “image” allowedTypes={"image"},. We will set the valueto the blockImageattribute.

After that, we sill add onSelectcallback which will be called after the user selects the media from the media library and the library gets close we will call a function here to set the selected image URL inside the attribute. For this also we won’t be calling the function directly here but we will declare the function on top like we have declared the variables before and use that function on callback.

We will create a function called onImageSelectinside our editfunction and before the return statement like shown in the code below:

const onImageSelect = imageObject => {
 props.setAttributes({blockImage: imageObject.url});
};

Inside that function, we will set the returned imageObjectin our blockImageattribute. And then call that function on onSelect={onImageSelect}.

Next is to use the render callback which is used to render the button which will be used to call the Media Library. Inside that render callback, we will use the ImageButtoncomponent which will use to open the Media Libray as shown in the code below.

render={({ open }) => (
  <IconButton 
  onClick = { open }
  className = "image-picker-button"
  icon = "media-image"
  showTooltip = "true"
  label= {"Change image."}>
    SelectImage
  </IconButton> 
)}

And that’s it with this our editfunction is complete.

Now we need to set the selected media in our savefunction. In the savefunction we will do the same first declare a constant to call the attributes easily.

const {
     attributes: { blockImage },
   } = props;

After that, in the return statement, we will create a container <div> <div>inside that div we will add an image container div and in that div, we will add the imgtag and set it to the source of the blockImageattribute.

<div className={props.className}>
    <div className={'image-container'}>
      <img src={blockImage} alt="logo" />
    </div>
    <figure className={'video-container'}>
      <div>
        <video controls src={blockVideo} type="video/mp4"></video>
      </div>
    </figure>
    <figure className={'audio-container'} data-type={"core/audio"}>
      <div>
        <audio controls src={blockAudio}></audio>
      </div>
    </figure>
</div>

And with that, we have successfully added an image to our custom block with Media Library support so users can set whatever image they want to set.

After completing the above code, we should be able to pick an image for our block and set it. Then when we publish that block we will see the chosen image. The complete source code of our new Media Block will as the code shown below:

const { registerBlockType } = wp.blocks;
const { MediaUpload } = wp.blockEditor;
const { IconButton } = wp.components;

import { ReactComponent as Logo } from "../logo.svg";
import placeHolder from "../place_holder.png";

registerBlockType("wpt/media", {
  title: "Media Block",
  icon: { src: Logo },
  category: "custom-category",
  descriptio:"A custom Block with Image, Audio, and Video.",
  attributes: {
    blockImage: {
      type: "string",
      source: "attribute",
      attribute: "src",
      selector: ".image-container img",
      default: placeHolder
    },
    blockVideo: {
      type: "string",
      source: "attribute",
      selector:".video-container div video",
      attribute: "src",
    },
    blockAudio: {
      type: "string",
      source: "attribute",
      selector:".audio-container div audio",
      attribute: "src",
    }

  },

  edit: props => {

    const {
      attributes: { blockImage },
    } = props;

    const onImageSelect = imageObject => {
      props.setAttributes({blockImage: imageObject.url});
    };

    return (
      <div className = {props.className}>
          <div className = {'image-container'}>
            <img src = {blockImage} alt="logo" />
            <MediaUpload
              onSelect = {onImageSelect}
              allowedTypes = "image"
              value={props.attributes.blockImage}
              render={({ open }) => (
                <IconButton 
                onClick={ open }
                className = "image-picker-button"
                icon = "format-image"
                showTooltip = "true"
                label= { "Change image." }>
                  SelectImage
                </IconButton> 
              )}
            />
          </div>
      </div>
    );
  },
  save: props => {

    const {
      attributes: { blockImage },
    } = props;

    return (
      <div className = {props.className}>
          <div className = {'image-container'}>
            <img src = {blockImage} alt = "logo" />
          </div>
      </div>
    );
  }
});

Add a Video in Block

Now let’s see how we can add a video inside our custom block, for learning purposes instead of creating another block I am adding the video in the same block. Now to add the video in the block steps will be almost similar to the adding image. So instead of starting again I will just highlight the changes and will share the full code at the end of the article.

First, we don’t need any extra components for adding video inside the block, components we have used for Image will work for video as well. The first change you’ll notice is in our attributes, in attributes I have created an blockVideo attribute with all the same parameters as blockImageexcept for the selector and the default. We have not used the default for the video and inside the selector, we added a selector for video.

Then we will create a function named onVideoSelectto save the selected media value inside our attribute.

In the edit function, we will first use the figuretag to wrap the video inside the figure we will add a div and inside that div, we will the videotag to and in the srcof the video tag, we will put the blockVideoattribute. MediaUploadand ImageButtoncomponents will be the same only change is into allowedTypeswe will add “video” as allowed type and the rest will be the same.

Inside the savefunction we will do the same as Image, we will create a video-containerwith <figure>tag inside that we will add a <div>tag and in that div we will add the <video>tag with source attribute set to the blockVideovariable.

Let’s see the changes for the audio in the custom block and then the complete code.

Add an Audio in Block

Now, we will add audio inside our custom block, and the process of adding audio in a Block is almost identical to adding a video with only a couple of changes.

First, we will create a similar attribute inside attributes for audio and name it blockAudioand we will only change the selector and the rest of the thing will be the same as blockVideo.

After that, we will create a new function named onAudioSelectto save the selected audio in the attribute.

In the edit function, the only change will be the figure className and the allowedTypewill be audio and the rest of the things will be identical to the video block.

To understand it properly checkout the code shared below. In the code, all three media types are used and are the final code of our media block script file.

const { registerBlockType } = wp.blocks;
const { MediaUpload } = wp.blockEditor;
const { IconButton } = wp.components;

import { ReactComponent as Logo } from "../logo.svg";
import placeHolder from "../place_holder.png";

registerBlockType("wpt/media", {
  title: "Media Block",
  icon: { src: Logo },
  category: "custom-category",
  descriptio:"A custom Block with Image, Audio, and Video.",
  attributes: {
    blockImage: {
      type: "string",
      source: "attribute",
      attribute: "src",
      selector: ".image-container img",
      default: placeHolder
    },
    blockVideo: {
      type: "string",
      source: "attribute",
      selector:".video-container div video",
      attribute: "src",
    },
    blockAudio: {
      type: "string",
      source: "attribute",
      selector:".audio-container div audio",
      attribute: "src",
    }

  },

  edit: props => {

    const {
      attributes: { blockImage },
    } = props;

    const onImageSelect = imageObject => {
      props.setAttributes({blockImage: imageObject.url});
    };

    const onVideoSelect = videoObject => {
      props.setAttributes({blockVideo: videoObject.url});
    };

    const onAudioSelect = audioObject => {
      props.setAttributes({blockAudio: audioObject.url});
    };

    return (
      <div className={props.className}>
          <div className={'image-container'}>
            <img src={blockImage} alt="logo" />
            <MediaUpload
              onSelect={onImageSelect}
              allowedTypes="image"
              value={props.attributes.blockImage}
              render={({ open }) => (
                <IconButton 
                onClick={ open }
                className="image-picker-button"
                icon = "format-image"
                showTooltip="true"
                label={"Change image."}>
                  SelectImage
                </IconButton> 
              )}
            />
          </div>
          <figure className={'video-container'}>
            <div>
              <video controls src={props.attributes.blockVideo} type="video/mp4"></video>
                <MediaUpload
                  onSelect={onVideoSelect}
                  allowedTypes="video"
                  value={props.attributes.blockVideo}
                  render={({ open }) => (
                    <IconButton 
                    onClick={ open }
                    className="video-picker-button"
                    icon = "media-video"
                    showTooltip="true"
                    label={"Change video."}>
                      SelectVideo
                    </IconButton> 
                  )}
                />
              </div>
          </figure>
          <figure className={'audio-container'} data-type={"core/audio"}>
            <div>
              <audio controls src={props.attributes.blockAudio}></audio>
                <MediaUpload
                  onSelect={onAudioSelect}
                  allowedTypes="audio"
                  value={props.attributes.blockAudio}
                  render={({ open }) => (
                    <IconButton 
                    onClick={ open }
                    className="audio-picker-button"
                    icon = "media-audio"
                    showTooltip="true"
                    label={"Change audio."}>
                      SelectAudio
                    </IconButton> 
                  )}
                />
            </div>
          </figure>
      </div>
    );
  },
  save: props => {

    const {
      attributes: { blockImage, blockVideo, blockAudio },
    } = props;

    return (
      <div className={props.className}>
          <div className={'image-container'}>
            <img src={blockImage} alt="logo" />
          </div>
          <figure className={'video-container'}>
            <div>
              <video controls src={blockVideo} type="video/mp4"></video>
            </div>
          </figure>
          <figure className={'audio-container'} data-type={"core/audio"}>
            <div>
              <audio controls src={blockAudio}></audio>
            </div>
          </figure>
      </div>
    );
  }
});

After adding the above code you should have a custom block with image, video, and audio. You can choose the different media for all three of them. As I have mentioned earlier I am not focusing on UI now so it will probably look crappy but it will function properly as you can see below.

Conclusion

Now we have learned how we can use different types of media inside our custom block and also how we can use a custom image for our custom block icon or as decorative or placeholder images. If you have any issues while following this article or have some doubts, questions, or suggestions make sure to comment on them below we will answer all of them.

You can get the complete source code used in this article and in the complete series on my Github repo.

Have questions or confused about something WordPress Related? Join Our Discord Server & ask a Question

Leave a Comment

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

Scroll to Top