As many of you know (or none of you, if you’re coming off a Google search or something), at Eastern Standard we are willing to do work in just about everything, though we have a strong focus on Drupal in particular, and sometimes we let WordPress out to play.
Most of our work is in Drupal 7 and 8, and this post is particular to Drupal 8. Some of you may also be coming from a marketing or business development area rather than from the developer’s cave … in which case, this article is not really for you. Although it can be if you follow along and maybe Google things sometimes.
When I started working here, I knew plenty of php and HTML and all kinds of fun computer and web things (and unfortunately XML), but the only thing I knew about Drupal was that it was a CMS that some people used sometimes. I have learned a lot about it since I started, though most of it was pretty specific to backend stuff that if done correctly nobody would ever notice happened. This is one of the few things I’ve done that’s actually directly visible to people aside from me, so I thought I’d share.
So, this is a blog about setting up, from start to finish, an image browser which supports images with manual crop styles and responsive breakpoints, aimed at developers and other technical people, and probably also people who are familiar with Drupal, although I’m not sure that’s required. This is literally the most exciting thing ever.* I have never done something like this before, so I figured “Hey, Drupal does both those things already, I should be able to knock this out with a bit of Googling!” Result: wrong. I found nothing. So I stumbled my way around, looking at documentations for various modules, clicking just about everything in the admin panel, and trying to figure out how to make Crop API and File Browser play nice with each other. I didn’t take notes the first time because I would have ended up writing down “do literally everything possible”, which is helpful to exactly nobody.
What follows is the result of setting this up and then destroying it when it was just a little bit off (this happened a few times, but don’t tell anybody that). After I got it mostly figured out, I wrote some barely legible notes about the process, which I ended up revising several times before they became actually useful.
The required module is pretty short**, so just enable all this stuff and you’ll be fine:
- Chaos Tools - Because basically everything in Drupal depends on this
- Crop API - So we can crop
- Paragraphs - Because I make this stuff modular! Paragraphs are good for that
- ImageWidgetCrop - More cropping related stuff
- DropezoneJS entity browser widget - This is a dependency, but we won’t actually use it
- Entity Browser - Dependency of File Browser
- Inline Entity Form - Does some black magic
- Entity Browser IEF - Lets us cram 7 into 9 and use it
- File Browser - The actual file browser bit that we’ll use
- Media Entity - Adds media entities (obviously) as a thing
- Entity - Dependency for Media Entity
- Media Entity Image - Adds an Image Provider to the Media Entity
- Media Entity Crop - Enables Crop API to work on Media Entity Images
- Media Entity Browser - Integrates Media Entities into File Browser. Also has a view we need
If you couldn’t tell from the required module list, we’ve got a lot of things that reference other things in a rather linear way. This will be common in this post. There’s no way to go from A to B without going over to L first, making a quick detour to Ω, and maybe stopping by the complex number plane for a bathroom break.
In addition to these, enabling Devel, Module Filter, Admin Toolbar, and Admin Toolbar Extras is also recommended, just because they make life a bit easier.
I also won’t go into detail on installing all of these. Check out their Drupal pages, as some of them have some library dependencies you’ll need to download.
Also, before you think you’re done, you’ll also probably need to patch Media Entity Browser (depending on if it’s been fixed at the time you’re reading this) with this patch: https://www.drupal.org/files/issues/meb_add_config-2850574-2.patch
I warned you this was aimed at technical/developer-y people. But if you can get all that stuff installed and working, you’ll be able to follow along with the rest of this (quite long) post without much difficulty.
CONFIG SECTION — The Good Stuff
First, we have to create our Crop styles. This part is the easiest part of the entire process. Just add whatever styles we need! Despite the simplicity of them, the crop styles are the most important part of setting up crops as they define the actual cropping. Using the crop behavior in Image styles is not as good for what we needed to do, but technically still works.
And for funsies, I’m adding a smaller crop, as well, which is identical to the first one, but with littler numbers. At this point, my crop styles page looks like this now:
If you need more crops, go ahead and add them. It doesn’t add much more work later, just a few clicks.
Second, we add our Image styles, which despite the name, are nothing like Crop styles. These define a set of behaviors, including Crop styles, to apply to an image, and are what are referenced later when an author actually uploads an image for cropping. First, add a Manual Crop effect and select the proper Crop style (since we [or at least I (but really “we”, since you’re following along, right?)] created 2 of them earlier).
I also add a Scale restriction so nothing janky happens, and I don’t allow upscaling because … ew, upscaling. A style for the small hero is also created, and like the Crop style, is basically the same. It’s important to have Crop before Scale in here; otherwise, you’ll end up with some massive black bars on the right and bottom of your image.
Next up is an optional step: If you are using Responsive Styles, add some responsive styles. These are possibly even simpler than Crop styles, but since it’s optional, I don’t count that.
Super easy! Now it’s time to get to the actual image fields, but don’t worry, we are only about halfway done. We head over to the Media Bundles area under Structure and create a new one. There’s a bunch of stuff on this page that we’re just going to go ahead and ignore for a bit; all we have to worry about right now is a name (and machine name), setting the Type Provider to Image, and maybe a description.
“But Spencer,” you’re now asking, “it’s been so long, and we still don’t have images!” Worry not, figment of my imagination! We are doing that right now. Go on and edit that shiny new bundle we just made and you’ll see a Manage Fields tab, which is where we get into actually setting up the image field. Again, this is a pretty standard part that a lot of people will probably be familiar with. Add a field of type image. Since this is a hero banner, I’ve limited it to a single image, and I put in some help text. Aside from that, I left it at the defaults.
Now, we have to set the form display to use ImageWidgetCrop and configure that. I also want to hide the Created, URL alias, and Publisher ID fields from the content managers. Thankfully, this part is also relatively straightforward (see a pattern yet?) Again, this is mostly defaults, I just tell the widget to use the crop styles set up earlier.
The display settings are also pretty similar: Hide the Created, URL alias, and Publisher ID fields, as well as the hero image label and Media name field. Since this is what regular users will see, we also need to configure the RESPONSIVE STYLES! If you’re using them, anyway. If not, just ignore the part where I tell you to configure them. Which is right now: configure them!
Now, here’s something very important to note: even though it looks like we’re done with the Media Bundle, we still have to resave it. Yeah, I know. So go back into the edit page, and despite everything being fine, hit save. If you miss this step, it will come back to haunt you later. You will see broken thumbnails in the media list, when editing content, and when choosing entities from the inline entity form. If you're already dealing with this problem, refer to this patch .
And now we’re done! Everything works! I lied to you again, there’s still a lot left to do (which is why there’s so much more stuff below). Now we move on to the VIEWS! Yes, that’s right. Views. Views and I do not get along. Thankfully, again, this step is pretty easy, as the base view is already created for us. So go ahead and edit the Media Browser view.
Click that “Duplicate Entity browser” button on the right above the Advanced area. I renamed mine “Entity browser (Hero Image)”. Now, we get to mess with the filters — just remember that to change the application to override and not All Displays (which is especially important if you’re going to have a bunch of these crop/browse fields):
This is more relatively simple stuff. Since this is a hero banner and not something that will be showing up elsewhere, I require the bundle to be the Hero Bundle we made earlier, require it to be published, and remove the translation. This last step I do because I don’t make sites in multiple languages, but if you do, I suppose you’ll need to configure that as needed (good luck).
Save that, and now we move on to mystery step eleventy four which eluded me for a while, and then escaped a couple times after I’d found it. We need to go configure an Entity Browser which is over under Configuration > Content Authoring > Entity browsers.
I like to set mine up as iFrame, Tabs, No selection display. Unfortunately at the time of writing No Selection display doesn't work, so you'll have to select Multi step selection display. You can use other setups, but I haven't tried them out yet.
BUT WAIT, THERE’S MORE! The next few steps I blew through and left at defaults, but the last one is important. This last step is where we tell the entity browser to use the view we copied made from scratch just before mucking with entity browsers. We have to add a set of widgets that control the behavior of the browser. But don’t go crazy yet, the only thing we want to add is View. The other options are possible probably (I haven’t tried them all), but the one we specifically do not want to add is the Upload widget, since the image field added to the Media Bundle handles that. All we want is View, elsewhere madness lies.
All we need to do is set the View : View display to the view from earlier, and maybe change the default label.
And now for a Paragraph! Alternatively, you can just add these fields to whatever you want, but we operate on modularity here, so having a paragraph type for a hero image lets us be more flexible, and even more configurable later (e.g., if you want to allow for different pairs of crops, like wide, tall, and square, or whatever) by setting a reference to multiple paragraphs.
So, create a paragraph and the first field to add will be a Reference to a Media type. Again, it’s a single hero banner for a page, so I limit this to 1. On the next page, restrict the Reference Type to the Hero Bundle we made earlier, and check off the Required Field box. After that, I add a caption formatted long text field that will be optional.
Now, the form display: This is where the magic happens. At long last, we will tell our Drupal site to use a file browser to browse for some files (it’s a crazy concept) that also happen to have crops applied to them. Neat.
So change that widget from a boring Autocomplete to a fancy Inline Entity Form - Complex and move on to configuring it. Check off that sweet Allow users to add existing media entities box to allow browsing (that part is important).
Configuring the display is also relatively simple: I hide the labels, move Caption below the Hero Image, and change the Hero Image to display as Rendered Entity.
Now, at long last, the final step: adding a reference to our new Paragraph on a Content Type (or wherever you want it). Just for the sake of demonstration, I’m adding this to the Basic Page content type that comes with a simple Drupal install. So, open that up, Add Field > Reference Revisions > Paragraph, label it, limit 1, basic stuff. Here, I make the paragraph field optional. That way, a hero image isn’t required, but if they add one, the image itself is required. The type is limited to whatever paragraphs we want (in this case just Hero Image). Leave the form display alone (or don’t, I’m not your mother) and hide the label in Display.
And that’s it. At long last, we’re finally done. It’s over. We can all go home. As long as nothing broke, in which case it’s time for troubleshooting. But if you’ve been following along with me, at this point, we should be seeing something like this on the Add Basic Page page:
Okay, so far so good.
Cool, the cropping works, both of our crops are there, thumbnails are being created and displayed, and now we see this:
Remember earlier when I said, “don’t forget to resave the Media Bundle, it’s really important”? I forgot to resave the Media Bundle. Luckily, that’s really easy to do, and 4 seconds later, the problem is fixed.
Doing it in a new tab, then hitting Edit and Update Media on the paragraph is enough to fix the problem. I dumped some Lorem into the body, saved the page, and saw all that beautiful work pay off! Then I tried viewing the page, and there was no cat. I forgot to update the media permissions! Again, this is a simple fix: People > Permissions, check off the boxes for Anonymous User and Authenticated User in Media > View media.
Now everything is working! Finally, after years of toiling, we have a page with filler text and a cat. If you followed along completely and set up the Responsive Styles, you’ll have a responsive page with the multiple crops working smoothly.
Holy moly, that was a lot of work. But does browse work? Let’s find out! Add content > Basic Page > Add existing media > select entities. It’s a lot of work, but that’s life.
Upload works, browse works, everything works.
This entire process took a long time for me to figure out. Each step by itself is relatively simple, but as is often the case with complicated tasks, that’s the best way to break it down into something manageable. Figuring out how to link all of them together to get from Point A to Point Z took a lot of poking and prodding and a little bit of guessing, but I got there.
That’s the approach I try to use on things I’ve never done. Eventually, after doing a thing enough, I learn where I can mess with the order of steps, or how to tweak very fine details, or do whatever. This process, for someone, was just “make a file browser for croppable images”. For me, it was a 36-step process that took a lot of trial and error, but now it’s also just a one step “make a file browser for croppable images”. After repeating these steps a whole lot***, this is now a single step for me, as well.
So I guess my point after all this rambling is that breaking a complex task down into a bunch of smaller, easier steps is the way to do a thing. But don’t break it down too far, or you’ll end up in a situation where you must first invent the universe.