Don’t go squishing my images

I haven’t done much with my website lately; apart from security updates, I’ve been too overwhelmed with work and life to write much this year. And what a year it’s been already! That’s not why I’m writing this post though.

I got the notification to update to WordPress 5.5 earlier this week, so I logged in, did the update, and glanced at a few pages to make sure everything worked okay. Usually it does, but this time, some of the images in my posts were looking pretty gnarly:

A quick element inspection showed me that WordPress was adding absolute pixel dimensions to all my images. I couldn’t even override it with CSS since it uses the width and height attributes on the image tag itself:

I think the absolute dimensions have been there for a while, but those attributes combined with my responsive layout and some block library CSS to make things look bad:

I tried a few different solutions to remove the width and height from my image tags before finding something that worked well. First, a post from CSS-Tricks (one of my favorite websites for advice on all things web design) suggested a couple of filters to use. Unfortunately, as I found out later, those filters only fire when an image is inserted into a post. The HTML is actually generated once and stored in the post instead of being generated dynamically as needed. I wanted to retroactively make this change for posts I’ve already published, and in particular I did not want to have to remove and re-insert images on old content.

I tried a few other filters including get_image_tag (yes, that page is for the function of the same name, but it’s also a filter which doesn’t seem to have its own page at the time of this writing) with the same result (that one also only fires on image insertion). Eventually, I found a Stack Exchange post that pointed me in the right direction.

My solution, roundabout as it is, is to modify all image tags in the the_content filter. That way, no matter when or how the markup was generated, my mini plugin will take out the width and height attributes, and the image will load with the right aspect ratio. I know there’s an argument for specifying the width and height so the browser knows how much space to reserve for the image, but that doesn’t make sense to me if it’s using the wrong height in the first place. I would rather make my pages load a little less smoothly in favor of my site rendering correctly when it does load. Plus, with well-optimized images, loading time is not really something I’m concerned about.

If you are curious how to reliably remove attributes from your images in WordPress, regardless of how long ago the posts they’re in were posted, here is my not-so-elegant solution to this very narrow niche of a problem:

function justincardoza_image_unsquisher($content)
    if(in_the_loop() && is_main_query())
        $document = new DOMDocument();
        $images = $document->getElementsByTagName('img');
        foreach($images as $image)
            if($image->hasAttribute('width'))  $image->removeAttribute('width');
            if($image->hasAttribute('height')) $image->removeAttribute('height');
        return $document->saveHTML();

add_filter( 'the_content', 'justincardoza_image_unsquisher' );

Building a Raspberry Pi security camera

Raspberry Pi computers are great for so many low-power applications, hence my obsession with them, and one of the popular projects I’ve read about is making one into a security camera. Home security and automation are topics I’m very interested in, so I went ahead and built a security camera to try the concept out. I decided to use a Pi Zero W for its small size and particularly low power requirements, and I was also able to find what I’m pretty sure is the original version of the Raspberry Pi camera on Amazon for less than $9.

Parts List


Before doing anything else, I flashed the MicroSD card with the latest version of motionEyeOS, a Linux distribution designed for video surveillance systems which runs on a wide variety of single-board computers including the Pi Zero W. I used balenaEtcher, the recommended tool for creating Raspberry Pi boot media, and the process was very seamless (apart from Windows complaining about the EXT partitions being “unformatted”). I didn’t even need to uncompress the boot image; balenaEtcher handled that for me.

The only other bit of software preparation you probably want to do is pre-configuring your WiFi information. This lets the camera automatically connect to your network when it’s done with its first-time setup. I just followed the directions on the motionEyeOS Wiki and it worked beautifully. All you have to do is create a file named wpa_supplicant.conf on the drive that Windows can see (that’s the /boot partition) and put this text into it, making sure you’re using Unix line endings:


And of course, make sure to substitute your own WiFi information (and country code if you’re not in the U.S.).


I thought the software would be the hard part and putting the case together would be a breeze, but it was actually the complete opposite. After inserting the MicroSD card, which as you can probably imagine went pretty smoothly, I ran into some issues installing the camera into the case.

The Camera Cable

Strangely enough, the cable that came with my official Pi Zero case had a wide strip of stiff plastic on the end with the connector for the Pi. It was actually wide enough to prevent the Pi from fitting into the case with the cable plugged in.

I estimated where to bend the cable based on how much of it would fit into the connector, then took it out and bent it by hand to avoid damaging the connector on the Pi. If your cable is flexible along its whole length, or if the part around the connector is short enough to fit into the case, you won’t have to do this.

Once your cable is ready, connect it to the camera and then to the Pi. The ribbon cable connectors are a little delicate, but all you really have to do is pull the little plastic bracket straight out, insert the cable as far as it will go, and then snap the bracket back in to hold the cable. The metal contacts on the cable should go towards the circuit board.

The Case

The next step is fitting the Pi Zero W into the bottom of the case. It may take some wiggling, but it will fit pretty snugly when it’s in place, and all the ports should line up.

Once the Pi is in the bottom of the case, fit the camera into the case lid. There are little plastic nubs to fit into the mounting holes on the camera board and tabs on the edges to hold it in place. If you use the cheap V1.3 camera from Amazon, don’t push it in all the way. The camera module doesn’t have quite enough clearance, and the case will actually put enough pressure on it to disconnect the camera module from the board.

You can easily snap the connector back in, but it’s annoying to have to do so. It looks like the camera module has double-sided tape on the back which has not been fully applied, and removing it or using it to stick the module to the board might help. I might try that next time, especially if I get an extra camera board.

After both the Pi and the camera are in place, just snap the case together. Then you can install the whole thing wherever you want, run the power cable, and you have a cheap indoor security camera running open-source software. As I do more with motionEyeOS, I’m sure I’ll write some more guides about what you can do with it. Stay tuned!

Protecting your hosted e-mail from spoofing

For a couple of months I’ve been getting a trickle of badly-put-together (but frustratingly well-spoofed) extortion spam at my main website e-mail address.

Some of the gems not shown here are “I am in shock of your reach fantasies!” and “My Trojan have auto alert, after this email is looked, I will be know it!”… then they ask for $928 in Bitcoin.

It didn’t bother me that much beyond my inability to track down the culprits (the spammers seem to be mainly using other people’s vulnerable ADSL routers in various countries to send their spam), but what really crossed the line for me was when I started getting delivery failure notifications for spam messages to other people:

Same basic idea, but this time they’re sending it to other people and putting my address on it. Destination address censored in case it does actually belong to someone.

Yes, the spammers were spoofing their messages to come from my address, and my domain wasn’t configured to give mail servers any rules about who is allowed to send e-mail from my address by default, so everything was being allowed through. I found some great resources like this Lifehacker article that explain how e-mail spoofing works, and I determined that I needed to add a Sender Policy Framework (SPF) record and a “Domain-based Message Authentication, Reporting & Conformance” (DMARC) record to my DNS settings.

Long story short, SPF tells mail servers who is allowed to send e-mail from a given domain name and DMARC tells mail servers what to do if a message is sent from an unauthorized server. They work together with SPF forming a security foundation for DMARC to build on. They’re both specified as TXT records and each has a specific format. I found some extremely helpful resources from DMARC Analyzer for putting together those records: they have guides for SPF and DMARC and even an online record checker for verifying that everything looks good.

I set up my DNS records so hopefully mail servers will now reject messages that I don’t personally send through my server, and I should now get reports about any future spoofing activity. I plan to write a follow-up post if I get any interesting results back from that. For now, stay safe out there and don’t give any Bitcoin to strangers!

Pimoroni heatsink case assembly

I recently got my hands on a Raspberry Pi 4 to add to my network thanks to Pimoroni, and of course it wouldn’t be complete without a cooling solution. Pimoroni also offers a heatsink case which both protects and passively cools the computer. Since the Pi 4 runs hotter than previous versions, I wanted to make sure it would have plenty of cooling, and this case was exactly what I was looking for. It gives 10-15 degrees of passive cooling according to their testing!

The design has been updated since the tutorial was written on how to put it together: there are now three contact points and three thermal pads, one each for the CPU, RAM, and USB controller. I think that’s a great change since there have been issues with the USB controller running hot on the Pi 4.

It’s pretty straightforward how to place the thermal pads, and apart from that the case assembly is the same as in the tutorial. This is how I arranged the pads to conduct heat to the case:

By the way, if anything goes wrong and you need new thermal pads, these are the dimensions to save you some time (they all look like 1mm thick thermal pad):

  • CPU: 13 x 14 mm
  • RAM: 15 x 9.5 mm
  • USB controller: 5 x 5 mm ( this could arguably be bigger to cover the whole chip package, but the contact point on the case is only about this big anyway)

It seems to work really well so far, and I feel confident that it’s going to cool the snazzy new Pi 4 efficiently. I don’t plan to do extensive thermal testing or anything, but it feels warm to the touch after a few minutes, so I know it’s spreading the heat out. This post isn’t sponsored in any way, I just really like the products featured here and I want to share information about how they work.

Lightbox plugin now available!

Yes, the custom lightbox plugin I developed for my website’s photos page is finally officially released! It is lightweight, functional, nice-looking (in my opinion at least), and it even does a little trickery when the page loads to make it a bit harder for visitors to download copies of your images.

I have a page dedicated to the plugin right here on this site, but more importantly, you can also find the plugin on and take a look at the source code on GitHub. Please do feel free to use it if it’s what you need for your website.

Putting everything in my pi-hole

This week I set up a pi-hole on my home network, and apart from a couple of minor hiccups, it has been very nice so far. If you haven’t heard of it, pi-hole is software that handles DNS requests and blocks online ads for every device on your home network, even on devices which won’t normally let you install a plugin like Adblock Plus (like smart TVs and un-rooted phones). The installation guide was nice and simple, and even setting up a DNS-over-HTTPS client was pretty straightforward.

One place where things got a little tricky was setting it up as my DHCP server. That’s very useful for improved statistics (requests will show as coming from the originating device instead of from the router) and just general usability (using pi-hole as a DHCP server also lets it resolve hostnames on your local network, as opposed to forwarding those requests to your router if everything goes just right). Once you disable DHCP on your router, whatever device you are using to connect to the router and pi-hole will most likely no longer have an IP address assigned to it. You need to set a static IP, connect to the pi-hole via its IP, and enable its DHCP server. Then once you switch your computer back to DHCP, you’ll get an address from the pi-hole and everything should work as expected.

I did also lose Internet connectivity the morning after I set up the pi-hole, and I ended up restarting all the network devices to get it back up and running. I’m not sure whether that was something going badly wrong with the pi-hole, old router DHCP leases expiring, or just my ISP-provided router/gateway coincidentally deciding not to work (that has happened before). Time will tell, although I’m hoping it was a one-time thing. I’m already liking it a lot better than ad blocking directly on my router, which was also nice, but not nearly as customizable or information-rich.

A quick note about PHP error logs

For some time I’ve been noticing a strange issue on my website: every once in a while, a file named error_log would appear in a subdirectory of my document root, visible to anyone who knew to look for it. It seems that whenever there was a PHP error (for example, when a vulnerability probe tried to access a theme file), PHP would dump the error message to a file in that same directory.

Those error messages contained absolute filenames within the server filesystem, so obviously that’s not something I want to be publicly viewable. I figured out that PHP has a setting for where to store error logs, and my web host had it set to just ‘error_log’. When there was an error message to output, PHP would send it to that relative filename, meaning the log file would show up in the same directory as the file where the error occurred.

Luckily, I have the ability to override PHP settings in a .user.ini file. The WordFence firewall (which I highly recommend, by the way) had already created one, so I just added a line setting error_log to an absolute path in my home directory. Problem solved! Now all my PHP errors go to a private file that the rest of the world can’t see.

Custom Windows 10 settings shortcuts

I have to change my proxy settings pretty regularly for work, so earlier this week I researched how to streamline that process a bit. The first thing I found was how to create a shortcut to a particular settings page. It’s relatively easy if you know the URI for the page you want, and there are plenty of lists out there, including this one at Windows Ten Forums. Just create a shortcut and put the URI of the page you want as the location. In this case I’m going to point the shortcut at “ms-settings:network-proxy”:

But… there’s a problem. I want this shortcut to be easily accessible in my start menu, but you can’t pin an “Internet Shortcut” to Start with just a URI as the target:

My workaround is to make the shortcut point to Windows Explorer and pass it the URI as a command line argument. That way, it’s technically not an “Internet Shortcut,” but it still takes us to that settings page.

And it works! This shortcut is pinnable to the start menu and takes me straight to the proxy settings.

Also, if you’re like me and don’t like the folder icon on the shortcut, you can totally change that too. Just right-click on the shortcut, choose “Properties,” and then on the “Shortcut” tab, click “Change Icon…”

<head> cleanup plugin now available!

Now that my website redesign is complete-ish, or at least launched, I’m starting to work on cleaning up and releasing some of the custom code I wrote to make it happen. This is one of those pieces: a tiny, lightweight plugin that removes unneeded stuff from the head section of each page to make everything a little more lightweight, improving loading times, bandwidth usage, and site security.

You can find an informational page about the plugin right here on my site, or just jump straight into what code there is over on GitHub.


Freeform windows in Android 10

I was very happy to find out that Android 10 ( R.I.P. dessert-themed version names) has support for freeform windows that’s easily enabled. It’s been around for a few years, but this is the first version of Android where you can get at it without using ADB or a third-party app.

The feature is exactly what it sounds like: it lets you open apps in resizable, movable, stackable windows like you can on a full-fledged computer running a desktop OS. I’ve imagined for years that this would be a nice thing to have, and it is pretty neat. It does have limited usefulness on a relatively small phone screen, so it makes sense that it’s still disabled by default, but it’s a nice option to have. It seems like it would be very useful when using a secondary display.

Here are a few things I learned from playing with it so far on my Pixel 3a:

  • You do really have to restart your phone after enabling the feature. It won’t work until you do.
  • Sometimes Pixel Launcher will crash when playing with freeform windows. That’s okay. (I’m using a third-party launcher, so that may be why)
  • Entering the multitasking view seems to dismiss any windowed apps you have open.
  • To get multiple windows open simultaneously, I’ve had success with the following roundabout procedure:
    1. Open the first app and switch it to freeform mode.
    2. Open another app and switch it to freeform as well.
    3. Reopen the first app from the homescreen (i.e. without going into the multitasking view).
  • Once an app is switched into a window, it seems to mostly stay that way until you tell it otherwise, even if you stop it and reopen it.

I can definitely tell this is still an experimental feature and there are plenty of bugs to work out. However, it is pretty exciting to see Google developing something like this, and I’m looking forward to seeing more refined versions come out in the future. In the meantime, I kind of want to see how it would behave with a secondary display and a mouse. I think that’s what I need to try next…