Safari vs. WordPress 6.7 Block Editor: Who’s to blame for forced PNG-to-HEIC conversion?

tl;dr update: I submitted a bug report about this issue to the WordPress Trac, it was fixed in 6.7.1, and I was even credited as a contributor to that version. Now on with the post…


Look at this image:


Now look at this one:


What if I told you those were the same image? Well… I mean… they’re not. Obviously. But they’re supposed to be. They were both the same image when they were on my computer. The same exact file. But I uploaded them to this page in two slightly different ways, and that made all the difference.

The one on top — the screwed-up one — I placed by inserting an Image block in the WordPress Block Editor, and then clicking the Upload button in that block, navigating my hard drive, and locating the image. The one on the bottom, I placed by again inserting an Image block, but this time I just dragged the image from a Finder window into the Safari window. WordPress supports drag-and-drop uploads.

Looking “under the hood,” I discovered that the file on top was somehow getting converted to Apple’s “High Efficiency Image Format,” HEIC (the reason for the C instead of an F is something I’ll leave to the Apple podcasters). WordPress just added HEIC support in version 6.7, which was released this week. Since browsers (other than Safari, I assume) can’t display HEIC images, WordPress automatically converts uploaded HEIC files to JPEG. And that’s why these two images look different. JPEG doesn’t support transparency, so the areas that were transparent in the original PNG got flooded with the nearest available colors1.

But, why should the results of these two upload processes be any different?

Well, after starting in the WordPress Support Forums and then moving over to the Make WordPress Core Trac and finally searching until I stumbled upon a year-old, barely active thread on the Apple Developer Forums, I discovered that Safari has a bug — I mean it has to be a bug, right? — where, if a file upload input field says it accepts HEIC format, Safari automatically converts the uploaded file to that format, apparently with no option not to do that. (I looked around all of the settings, even the developer ones, and didn’t see anything about this “feature” at all.)

And sure enough, WordPress 6.7 is a bit haphazard with its “support” of HEIC uploads, which made it easier to confirm the cause. There are two ways, generally speaking, that WordPress handles file uploads: the browser upload, via an <input type="file"> HTML field, and a JavaScript/AJAX/React/whatever drag-and-drop option.

The <input type="file"> field in the Image block of the Block Editor has added HEIC support via the accept="image/heic" attribute. But the input field in the old school Media Library upload page has not been similarly updated. (It’s become a fact of life in the WordPress world that most of the core team’s attention is on Block Editor stuff these days, and older features get ignored.) Uploading images in the Media Library does not do the conversion. Likewise, whatever exactly is going on with the drag-and-drop method also does not involve the accept="image/heic" attribute that causes Safari to do its mischief.

Unfortunately, it looks like the only “solution” at this point would be for WordPress to do a browser sniff and remove the accept="image/heic" attribute if the browser is Safari. The only reason that was explicitly added was to get Chrome to support HEIC uploads; as I understand it, Safari would support them regardless, but explicitly declaring HEIC support is apparently what triggers Safari to make the conversion.

So, practically speaking, Safari users who want to upload PNGs to their WordPress sites just need to be sure to only upload via drag-and-drop, or the Media Library.

(I haven’t tested, but I suspect JPEG uploads are likewise getting converted to HEIC and then back to JPEG, which probably results in a reduction of image quality.)


Side note on how I discovered this in the first place: Two days ago I was writing another blog post somewhat critical of Apple, and I found when I was trying to upload a screenshot of a window from my Mac — Mac screenshots are saved as transparent PNGs — the transparency was turning black. I was so driven to distraction over the situation that I barely managed to finish writing the post.

1 Saying those areas are flooded with color is an oversimplification. It looks like the color of each pixel is being determined consistently with how PNG compression works.

Elementor and the popularity feedback loop

I hate Elementor.

If you don’t know what Elementor is, good. If you do, you probably either hate it too, or else you’ve never used WordPress without it. (And even if you haven’t ever used WordPress without it, you still might hate it.)

In my experience, Elementor is hot garbage, and it makes the overall WordPress experience bad.

It’s not just Elementor. There are several “page builder” plugins for WordPress, and they’re all terrible. Divi, WP Bakery, Beaver Builder, etc. They all deviate wildly from the way WordPress is intended to work. Since 2018 WordPress has had the Block Editor (a.k.a. Gutenberg) built-in, which is essentially a page builder itself. Now that Gutenberg has matured enough to be useful, those other page builders are completely unnecessary.

Among the page builders, I think Elementor is the worst. Why? Mainly because of its ubiquity.

Elementor is extremely popular, in part because there’s a companion theme/gateway drug called Hello Elementor. It is the most popular third-party WordPress theme, as evidenced by its lofty position at the top of the WordPress theme download screen, surrounded by the official annual themes and one other third-party theme, Astra. (I actually really like Astra, because for the most part, it does things the WordPress way.)

Why is Hello Elementor so popular? Presumably people do like it. But I think it is also an example of what I would call the popularity feedback loop. It’s a natural, and harmful, side effect of a page like this, also commonly seen on e-commerce sites.

If you sort things by popularity, with the most popular items at the top, those are what people are going to see first. And most people don’t want to spend a lot of time considering options. They may trust popular opinion, or they may be too impatient to consider their options carefully, or they may just not care at all. So they click on the first thing that catches their attention, thereby making the popular thing even more popular, and dooming less popular options to oblivion, regardless of their quality.

The people choosing to default these lists to ranking by popularity may think they’re making an objectively straightforward choice, but they’re not considering how the popularity feedback loop might have much more of an effect on the rankings than quality, because they’re falsely assuming that people are making careful, rational choices.

There’s another reason in this specific context why it matters. New users don’t understand the WordPress ecosystem. They don’t know about third-party themes and plugins. They don’t know what does or does not adhere to “the WordPress way.”

So, a new user comes in and wants to pick a theme for their site. Their eye is drawn to the Hello Elementor screenshot, which has been carefully designed to be attention-grabbing, especially compared to the rather pedestrian appearance of the official themes.

That’s all fine in and of itself. Third-party themes are great! But when you activate the Hello Elementor theme, it immediately starts prompting you to install the Elementor page builder plugin as well. If you’re not an experienced user, what are you supposed to do with this? You probably install it, of course. And now you’re in page builder land. It’s not WordPress anymore. The experience is completely different.

But what is it about page builders that’s so bad? (And this part really applies to Gutenberg to a large extent as well.) They’re supposed to be making it easier to design your web pages, right? Well… there’s only so much you can do to make designing a web page easier. There’s no way to deal with things like margins or padding without understanding what margins and padding are. The page builders end up being CSS GUIs. Maybe you’re not writing the code, but you still need to know the concepts to get anywhere. So you end up either creating a convoluted mess, or at best you do learn the concepts, but in a compromised way, that is inextricably tied to that page builder plugin. It’s lock-in.

I could go on, but I think there are two main ways to address the problem of the popularity feedback loop, at least as it applies specifically to WordPress themes, but also more generally:

  1. Don’t default to a “most popular” view. I know it takes a lot more work, and is a lot more subjective, but the best default would be a “recommended” view. Some editorial decisions need to be made. Consider popularity, of course, but also consider context. Which themes are the best for a newcomer? Which ones offer the most pure WordPress experience?
  2. Make the “most popular” list conditional. This is a more automated version of #1. Maybe you don’t have a carefully curated editorial list of recommendations, but at the very least, determine some criteria that can restrict what shows up in the list. For starters, maybe a theme cannot load with an admin notice pushing users to install a plugin. Would Hello Elementor be such a problem if it didn’t immediately lure new users into installing a page builder plugin too? Probably not.

Ultimately, I have my own selfish motivations in all of this. I develop a number of WordPress plugins myself, and I need to provide user support for them. And a significant percentage of my overall user support load — I would say it’s around 15-20% — is around conflicts with Elementor.

The final (?) verdict: Gutenberg (a.k.a. the WordPress “Block Editor”) is fundamentally flawed and unsustainable

I’ve been trying. Really I have.

From its initial release as part of the WordPress core in version 5.0 in late 2018, up until early 2022, I adamantly refused to use Gutenberg. I felt its conceptual flaws and practical limitations were so profound and so obvious that I really could not believe this was going to be “the future of WordPress.” And now here we are.

In the spring of 2022 I finally relented, as at least the initial impression of the user interface had improved to a point where I felt I just needed to embrace it or move on. And so I created a new base “Block Theme” for future WordPress projects, and began building new client sites with it.

The past year and a half of dealing with Gutenberg more directly has been a painful rollercoaster of emotions, as I’ve tried repeated to convince myself it’s good, only to have it, once again, prove itself a hot mess of ill-conceived and barely-documented hacks.

Many times in the past 18 or so months I have contemplated abandoning WordPress for good, checking out ClassicPress and some other CMS options before falling back on giving Gutenberg another chance.

I’ve even considered writing my own Content Management System (CMS) [again; it’s something I specialized in before 2014]; switching to Drupal, for God’s sake (until I read that they’re porting Gutenberg for Drupal too… why why why?!); scrapping CMSes altogether in favor of just building sites with Bootstrap (and giving clients some rudimentary editing tools for the very few elements of their sites most of them actually modify post-launch); and even quitting the field entirely.

Frankly I don’t have the time or energy to make an extensive, coherent case for why Gutenberg is so fundamentally flawed; suffice to say it’s a combination of four main issues:

  1. frustrations over its excessive reliance on React (the Flash of the 2020s) for so much of its functionality,
  2. irritation at its embrace of the “make the interface seem simple by just hiding everything until the user hovers over the right magic spot” approach to UI/UX design,
  3. trying to get a handle on how the damn thing works, due to its combination of woefully inadequate and outdated documentation, and the fact that it is constantly changing, in ways that break my code (which was written based on earlier assumptions about how things worked, because that was all I had to go on), and
  4. its absolute, unforgivable abandonment of the core web design principle of separation of content and presentation.

The last one is really the killer, and it is only getting worse, because not only does the code — that fragile, convoluted, redundant code, stored in the database — become increasingly unmanageable the more you build your site, but WordPress is constantly pushing more of its structure into this disastrous framework (if you can call it a framework). The Site Editor is a true abomination that can’t possibly be useful to anyone… except possibly “no code” website builders. But honestly, if you can’t write code, you should just be using Squarespace instead of WordPress. You’ll be much happier, and so will your clients.

All of these issues probably stem from one even more basic to the whole discussion though: the creators of WordPress (especially imperious leader Matt Mullenweg) do not consider WordPress to be for what most of us “WordPress professionals” actually use it for. To them, it is blogging software. Period. But very few people who make a living in the WordPress ecosystem are using it to build blogs. Instead we are using it as a general-purpose CMS.

Gutenberg is adequate for a basic blog — in fact, I’m using it for this one, and I do prefer editing my posts in Gutenberg vs. Classic Editor. Its severe flaws and limitations don’t become readily apparent in the “basic blog” context.

There’s an argument to be made that Gutenberg really exists for WordPress.com to compete with the likes of Medium and Substack, and the industry of us web professionals who use the open source version are of no consequence to Matt’s vision for the platform.

Anyway, I have managed to launch about ten new client sites in the past year-plus using WordPress with Gutenberg, and every time I have had to face frustration and embarrassment as I acknowledge with clients the limitations of the tool, or sympathize with their frustrations in dealing with it as users.

My current project may be the last straw though. I’m two days away from launching the biggest site, by far, that I’ve built with Gutenberg. It’s over a year in the making, and now at the eleventh hour I am confronting the possibility of having to manually edit a huge number of posts in a CPT I created — and naively used the Block Editor to manage instead of just some ACF fields — because the client wants to change the default text sizes.

It’s possible this situation could be remedied by the merger of Block Patterns and Reusable Blocks that happened in WordPress 6.3, but guess what… we had already created all of this before that functionality was an option. I still haven’t had time to even figure out exactly what the implications of these 6.3 changes are, because I’ve been too busy just trying to build the site.

That’s where WordPress is really dying for me as a viable platform to work on. It’s supposed to be the foundation for what I do, but now the ground is constantly shifting beneath my feet. Gutenberg is making web development much harder and more frustrating, projects are taking longer, and it’s making me look incompetent and unprofessional to my clients. I’ve been a professional web developer since 1996; I’ve been using WordPress for projects since 2008, and almost exclusively since 2014. But now I don’t trust it anymore.

I’m in a position where I may (fingers crossed) be able to back off taking on any new freelance projects for the remainder of the year, once this site has launched. I am really hoping that’s the case, because it’s time for me to make a serious re-evaluation of whether or not I want to build any more WordPress sites in the future, and if not, I need to take that time to learn — or build — a new platform.

The great irony, of course, is that my business has increasingly been made up of selling and supporting my commercial WordPress plugin, ICS Calendar Pro. Fortunately, my work on that plugin has very little to do with, nor is significantly impacted by, the Gutenberg/Block Editor project, although that may change as WordPress continues to (d)evolve.

(Don’t even get me started on how bad Gutenberg is for responsive design.)

One document that encapsulates the Block Editor core team’s detachment from the reality of how most professionals actually use WordPress

That would be this document.

Establish early what content you expect to require updates

At a high level, it’s important to recognize that not every piece of content can be updated across the entire site and that the method of creation greatly impacts what’s possible. As a result, it’s critical to spend time ahead of creation determining what you expect to need updates and to put that content in the appropriate format. This will make a huge difference in terms of future maintenance.

Embrace theme design at the block level

Block theme design requires a mindset shift from the previous approach of designing large sections of a theme and controlling them via updates. While a holistic view of a design is still important when creating a custom theme project, blocks require that themers approach design on a more atomic level. This means starting from the block itself, typically through theme.json customizations. The goal is that each individual “atom” (i.e., block) can be moved around, edited, deleted, and put back together without the entire design falling apart.

The more that you approach design at the block level, the less need there is to propagate updates to things like patterns and templates across the entire site. If the atomic pieces are in place, their layout should not matter.

Gee that’s rich. My particular issue right now is that I need to make some updates to a block pattern I created for my client’s site. Unfortunately, that block pattern was already in use on about 40 pages of their site, but it involves an unanticipated design issue. (As it happens, yes I probably should have thought it through a bit more before it got propagated so extensively, but the practical reality of building websites is that sometimes you don’t know what will or will not be effective at the outset — especially when you’re simultaneously dealing with end users learning how to wrangle Gutenberg — and one of the great features of the web from its inception to today is that things are easy to change later on. In fact, that has been a driving force behind template-oriented CMS platforms from the beginning. It’s the separation of functionality, design and content that has been at the heart of most well-structured website editing platforms, including WordPress, until now.

It’s easy, when you believe that what you are creating is a blogging platform, that people only use it to create blog posts that are content-heavy with mostly one-off layouts. And yes, that’s how WordPress started. But the entire team must collectively have its heads deeply inserted up Matt Mullenweg’s ass (sorry for being crass, but I’m also being honest) if they think that’s how WordPress is predominantly used, if that’s what made WordPress as big as it is. Because it’s not.

I’ve been doing “block-based” design with WordPress sites (using Advanced Custom Fields and its wonderful Flexible Content field) since well before the Gutenberg project existed. But I had a much different, less “atomic” concept of blocks. This atomic approach is great (I guess) in concept, but it is too fine-grained to be a useful tool for the average web content editor, and it makes design and development orders of magnitude more difficult and time-consuming.

I have now completed four site projects using my own custom block-based theme, and have three more underway. While there are some really “cool” features of the Block Editor (Gutenberg), these projects have also taken me much longer and been far more maddening to build, and have left my clients much less confident in their ability to easily edit their content, than anything I had done in the previous decade of working primarily with WordPress.

And this last set of three projects is in many ways a rolling back of features, because after too many months of frustration with the limitations of block themes, “version 3” of my custom theme actually reverts from using the new HTML-based page templates to using PHP-based templates. It’s a regression in a way, but I never had any intention of using the Site Editor anyway, because it’s not an easier way for me to build sites, and it grants access to elements that should be 100% hands off for the clients who’ve hired me.

And now, once again, I’ve been derailed from my work by the need to spend 45 minutes venting my frustrations over this predicament in a blog post.

By the way, I'm aware of the irony of using Gutenberg in order to decry it, so don't bother pointing that out.


So… how did I end up resolving the issue of updating the block patterns that already appear in my content? Do you really want to know? I fired up phpMyAdmin, wrote a SQL query to find all of the affected instances, and manually copy-pasted the update into them. (Yes, I could’ve written a SQL statement that would just do the replacements; I tried that first, but the replacement text was really long and was generating a MySQL error that I couldn’t quickly pin down, so it was faster to just manually edit the 40 records.)

A simple way to add responsive (breakpoint-specific) blocks in Gutenberg

The new WordPress Block Editor (a.k.a. Gutenberg) has improved immensely over the years, to the point where I am now willingly (although occasionally grudgingly) using it as my main development platform for client sites.

One area where it really falls down though is in smartly handling responsive breakpoints. There is some effort to make it responsive-friendly (though it’s definitely not “mobile first”), but there are really weird holes, like the fact that there’s no built-in way to apply consistent left and right margins on text content at smaller screen sizes; once you’re below the defined content width, if you don’t manually configure your theme to add padding/margins to headings, paragraphs, etc., and they don’t have a defined background color, the text will bump right up against the edges of the screen.

That’s not the problem I’m here to solve at the moment, however. Instead, I want to focus on a handy little tool I’ve been using in my WordPress development for over a decade: specialized CSS classes to designate blocks of content as only appearing on phones, or not appearing on phones.

By “phone” here I just mean the smallest standard breakpoint. I’m using the WordPress convention (at least it used to be the WordPress convention; I don’t feel like I can trust anything anymore) of setting that at the slightly odd (although even) value of 782 pixels.

What can you do with this? Once you have CSS classes that designate a block as only appearing on phones or not appearing on phones, then you can easily tailor your output to certain screens. Obviously (at least, I hope it’s obvious) this is not the ideal solution; it means you’re delivering HTML content — potentially redundant HTML content — that will not be seen by some users. But nothing in web development is perfect, and this can be a convenient way to get out of a pinch when, for example, you have a very complex desktop layout element that simply cannot be adapted in a usable way on phones. You can just hide that element on the phone breakpoint and, if desired, present the same content in a more simplified way to only phones. (Again… only if you can’t achieve a usable phone experience on the same HTML block via media query-specific CSS.)

OK, let’s get down to it. The first thing you need to do is register a couple of block styles. I am only making these styles applicable to the Group block, because that seems like a logical way to rein it in. Any block can easily be wrapped in a group, so if you need this feature, just do it.

register_block_style('core/group', array(
  'name' => 'no-phone',
  'label' => 'No phone'
));

register_block_style('core/group', array(
  'name' => 'phone-only',
  'label' => 'Phone only'
));

That should go into your functions.php file or wherever in your theme you are defining block characteristics. Ideally it should be in a function that is executed on the init action. Next, you need to make sure you’ve got a custom block style .css file enqueued for the Group block. You can place this wherever is appropriate within your theme; I happen to have a nested assets/css/blocks folder where I put mine. Here’s that bit of code, also for your function that runs on init.

wp_enqueue_block_style('core/group', array(
  'handle' => 'my-theme-core-group',
  'path' => get_theme_file_path('assets/css/blocks/core-group.css'),
  'src' => get_theme_file_uri('assets/css/blocks/core-group.css'),
));

And then in the referenced core-group.css file, you’ll need this:

@media screen and (max-width: 782px) {	
  .wp-block-group.is-style-no-phone {
    display: none !important;
  }
}

@media screen and (min-width: 783px) {
  .wp-block-group.is-style-phone-only {
    display: none !important;
  }
}

Now in the Block Editor, when you switch to the Styles tab when focused on a Group block, you’ll see your new style options: