WordPress Gallery
Ugh, so the WordPress built-in gallery content type seems broken again. I’m not sure it’s worth bothering about. If i fix it locally, it’ll just break again on some future update.
Ugh, so the WordPress built-in gallery content type seems broken again. I’m not sure it’s worth bothering about. If i fix it locally, it’ll just break again on some future update.
We used to have a lot of physical devices on our network*. Servers, firewalls, file-shares, staging servers, development machines… all sitting on the network with their hard drives endlessly spinning, spinning, spinning!
System administrators are fond of referring to platter-based hard drives as “spinning rust,” partly as a reference to the ferro-magnetic iron crystals that store the actual data, but also to remind us that it’s always decaying and corroding. Over time, drives start generating errors or becoming unreliable. When we had physical devices that exhibited issues, we’d yank the hard drive and replace it. Over the years, we’d accumulated a pile of a dozen or more drives that were unreliable or bad but still contained data.
The data is not especially sensitive, but there could be stuff that could be abused or belongs to other parties. There may well be meeting notes, source code, sample data files, or there could be cached passwords or other credentials. It’s not worth just hoping it’d be OK to release to the world. So it’s a chore to render this data unreadable.
Pulling apart spinning platter hard disks is humbling. These are incredible little devices, with incredibly precise machining and elegant engineering. Going through a pile that spans a decade, you can actually see the improvements in technology: new vibration damping systems, different head-parking strategies, traps for dust, and more. I see these parts, and am inspired by the craftsmanship that goes into them.
So in the spirit of admiration, I offer these (hopefully unreadable) holiday memories.












* Now, of course, we have few physical devices but all those same services are implemented on “the cloud.” This means that someone else has physical devices somewhere, with their hard drives (or SSDs) endlessly spinning, spinning, spinning (or trimming, trimming, trimming).
Every time this happens, I get confused and lost, and have to rediscover the solution. So here’s a note to future self.
Symptom: PHPStorm stalls on an SVN update, and sits there doing nothing. Network is OK. SSH into server that supplies SVN, watch the WebDAV logs, and there’s nothing even trying to talk to it.
PHPStorm is configured to use an external Subversion client.

Solution: Don’t (necessarily) go and mess around with the settings for PHPStorm. Open a terminal, go to the working set in question, and do an “svn up” from the command line. This is where you’ll discover that SVN has either identified the server certificate as expired or updated, and it’ll ask you to approve the certificate (in that latter case). Log in with your credential again. Now it’ll all be OK again.
I have long wanted to be able to post visual stories where I can show a map of a place with specific pictures. If you go to the “Map View” of iOS Photos, or the “Map” view in Adobe Lightroom Classic, you can see sort of what I was looking for. There are many ways to view geo-tagged photos on a map, but not as many to be able to create a map for sharing.
What I wanted was to be able to tell a visual story, like a hike or travel day, and have it displayed in context. I wanted to be able to place this in a blog (perhaps even here!?). I wanted it to be easy: throw a few geo-tagged photos into a directory, run a script, and get my annotated map and scaled images. I saw there are WordPress plugins that will do this available for purchase, but they all rely on Leaflet or Google Maps and involve a lot of view-time dependencies. Furthermore, I don’t like Google Maps because anyone who views my story would be tracked and analyzed by the evil advertising algorithm.

The WordPress plugins are also more interactive than I need. I don’t necessarily want the ability to zoom, or scroll away from my specified region, or list all of the restaurants within the view.
So, to make a long story short, I’ve started to write the script I want. It’s an ugly PHP script that reads the geographical data from a folder full of JPGs. It uses a free account at MapBox to download map tiles and assembles the background. Then it draws the locations of each photo along with a direction indicator (also extracted from the EXIF data of the photos), ordering them by the time the picture was taken. It scales the images to a web-appropriate size, then it slaps together a primitive web page with the labeled map and just enough Javascript to display the photos in a “lightbox” effect when you click on the location. Once it’s generated, there are no external dependencies and the entire thing fits in about 4 kilobytes (not including the images).
Here’s an example in Ventura, California, and another in Mar Vista, California.
These raw outputs are fine, but if I wanted, the HTML is easy to edit to make more friendly. For example, I could replace the filenames in that right-hand column with descriptions.
There are some interesting challenges. It turns out the coordinates that the iPhone injects into the EXIF data are usually pretty accurate, but when I wandered around a small park and took pictures, in some cases the coordinates were off by a dozen meters or so. The compass direction tends to be more accurate, except in rare cases where it’s completely way the heck off. I don’t know if it’s magnetic interference, the fact that the orientation of the phone changes when one lifts it to take a picture, or what is the cause.
I should probably come up with a better strategy for overlapping photo points. It might be nice to anti-alias the circle that’s drawn. I could also potentially avoid drawing on the map at all, but rather use CSS to draw the locations within the web page. That would allow easier visual customization (at the expense of bigger file sizes and more complexity).
At some point, I should also get over my embarrassment, and open source the code.
So, it was another plugin-gets-updated-and-the-site-crashes situation. It’s not exactly the fault of the plug-in. It’s WordPress being stupid about security.
As I wrote back in 2019, I have WordPress automatically updating itself and its plugins using a cron job that uses the magical Word Press CLI. Notably, this update process runs as a different user than the web server. This is by design. I want to minimize the number of directories where the web server has write permissions — especially, I don’t want it being able to write in the directories containing code. This is kind of basic stuff. If someone can abuse a bug in the core or a plugin to write a file in the web tree, they could do all sorts of mischief even without escalating privileges. Denying the web server write access to those areas is a simple mitigation that prevents a whole class of attacks.
WordPress, however, was written with the belief that it should be able to write files wherever it damn well pleases. The idea is a naïve user gives WordPress full write access on their server, or their FTP credentials to their host, or their ssh username and password [!!], and then a lot of functionality is simplified. Once the web server has privileges to write everywhere, it’s easy to give the user the ability to install, update, edit, and remove plugins and themes directly from the web interface. Very convenient! Especially if you don’t have trust issues like I do.
Now, because of the way content is uploaded and plugins work, there are always going to need to be directories where WordPress has write access. That’s fine. I can protect some of those from being a problem by setting directives in the web server to prevent code execution.
There’s a lot of infrastructure to support WordPress’ profligate write permissions. One component of this is an internal function WP_Filesystem that creates a global abstraction of the filesystem. Once that function is called, plugins or themes or whatever can call methods on the global $wp_filesystem variable to interact with the filesystem, while behind the scenes these interactions could be directly, over FTP, over ssh, or other protocols, depending on how the system is set up. Instead of calling file_put_contents(...), for example, the plugin author calls $wp_filesystem->put_contents(...), and doesn’t have to worry about the details of which protocol is used.
The WP_Filesystem function works by calling the function get_filesystem_method in wp-admin/includes/file.php, which tests different ways of writing files. Here’s where I got screwed. To see if it can write directly to the filesystem, this method tries to write a temporary file, and if this succeeds, checks the ownership of the created file. It compares that to what it considers the WordPress file owner, which is determined by looking at the ownership of wp-admin/includes/file.php. If that fails, it moves on to the next protocol.
So in my case, get_filesystem_method didn’t think it could access the filesystem directly, because wp-admin/includes/file.php was not owned by the web server user. So it moved on to try to update via FTP, ssh, etc, and all failed. It then gracefully threw an error that took down the whole site.
Now the question is why this plugin update needed write permissions anyway? The files making up the plugin were installed successfully by my upgrade script. It turns out that the plugin had a new stylesheet in an scss file, and on the first run it was trying to compile it. I’ll grant that that’s a reasonable case. But the directory where it wanted to put that compiled css was writable! It just never got to that point, because of the abstraction layer.
The slightly ridiculous solution to this problem was to change the ownership of wp-admin/includes/file.php to the web server user, load the main page of the web site to let it generate the css, and then change the permissions on that file back. Stupid, stupid, stupid.