Hosting WordPress inside a SilverStripe Installation

I ran into a puzzling issue today. Normally I wouldn’t recommend hosting a CMS inside another CMS installation, but for various reasons, I had to set up a WordPress blog inside an existing SilverStripe installation. For sake of this article, I’ll call it example.com/blog/.

The first problem I ran into was that instead of loading WordPress, example.com/blog/ was showing the directory index:

SilverStripe WP Directory Listing

That’s obviously not ideal, as well as being a bad idea for security.

I then added Options -Indexes to the WordPress .htaccess file to disable the directory listing, but all I got was a “403 Forbidden” error when going to example.com/blog/ or example.com/blog/wp-admin/ (however, example.com/blog/?p=1 would redirect to the post URL using pretty permalinks and worked fine 🤔):

SilverStripe WP directory forbidden

I then tinkered with the SilverStripe .htaccess file, thinking it was overriding something; I added this line to make it ignore the WP blog URLs:

RewriteRule ^/blog/?.*$ /blog/index.php [L]

Still no luck.

Finally, I thought to try manually setting the index file, so added this line at the top of WP’s .htaccess file:

DirectoryIndex index.php

And that did the trick!

There must have been a server-wide setting to use some other file for DirectoryIndex (that’s the file that gets served by default when you try to access a directory URL), but I didn’t have access to the entire server.

Summary

Here’s what I ended up using:

SilverStripe .htaccess file

RewriteEngine On
RewriteBase '/'

# Added for WP blog
RewriteRule ^/blog/?.*$ /blog/index.php [L]

# Process through SilverStripe if no file with the requested name exists.
# Pass through the original path as a query parameter, and retain the existing parameters.
RewriteCond %{REQUEST_URI} ^(.*)$
### Blog Redirect ###

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* framework/main.php?url=%1 [QSA]

WordPress .htaccess file

DirectoryIndex index.php
Options -Indexes

WordPress Theme Stylesheet Auto-Cachebusting

If you’re like me and you set up server-side caching, CloudFlare (or any other proxy cache), and/or long Expires headers on your theme stylesheets, you know the hassles that go into invalidating those caches and forcing browsers to load an updated version.

One method to force browsers to pull the new version is to add/change the ver parameter in the query string (WordPress’ wp_register_script, wp_register_style, wp_enqueue_script, and wp_enqueue_style have a built-in way of doing this).

Query Strings

Defining a Constant

Here’s how I used to do it: define a constant and then manually update that, as well as the Version header in the style.css file.

The main drawback is that I had to manually update the version number in two places: functions.php and style.css.

File Modification Time

Another method I’ve used at times is to add the style.css file modification time as the query string.

This has the advantage that the cache will be invalidated every time the stylesheet file changes. For some reason, I really never cared for it that much, though. It does add a tiny bit of performance hit, as the filemtime has to go get the file and figure out the timestamp.

WordPress Theme Version

I just read about this today and I think it’s going to be my go-to method in the future. It uses one of WordPress’ built-in theme functions to get the version number from the stylesheet.

This has a bit of overhead as well due to the function call, but I like the fact that it uses the theme version number so you can easily do Semantic Versioning.

Filename Modification

However, most performance testing tools will recommend you remove query strings altogether to improve caching especially by proxy servers. Here are two automatic methods of doing that:

File Modification Time

WordPress Theme Version

Conclusion

No matter which method you choose, setting up caching can greatly improve your site speed. It’s worth a little bit of hassle to ensure your stylesheets and scripts are cached, knowing that with any of these methods, you can easily invalidate those assets.

WordPress and Responsive Images: srcset and sizes Attributes

I’ve been puzzling over a performance issue on one of my sites lately and finally got it figured out today.

A custom shortcode uses the_post_thumbnail() to include a small image (~250px square); I have a bunch of custom image sizes set up, so the srcset attribute included 16 different image sizes. (Overkill? Maybe….) However, instead of using the image closest to 250px wide, Chrome was pulling in the largest available image—sometimes as much as 1500px! Obviously, this is terrible for performance.

In addition, certain pages had dozens of these images, multiplying the effect. My test-case page was 10+MB total (way too heavy…).

Here’s a sample <img> tag for one of my images:

I finally realized that the root cause was that the sizes attribute was set to “100vw,” basically suggesting to the browser that the image might at some point be rendered at 100% width of the viewport, so my browser was happily pulling down the largest possible image so it could display it in all of its high-resolution, hundred-KB glory instead of the scaled dozen-KB file.

Since I know this particular shortcode will only show images at a max width of 250px, I needed to set the sizes attribute to “250px,” hinting to the browser that anything slightly larger than that would be perfectly adequate.

Here’s how I handled it:

  1. Added a filter to wp_get_attachment_image_attributes and checked for a named image size or array
  2. If it was an array, I set the sizes attribute to that pixel size
  3. If it was a named image size, I set the sizes attribute to that pixel size

Sample code:

This approach admittedly is a bit heavy-handed and I’m still testing out the behavior on other pages on the site, but this fixed the problem with that specific shortcode, and my test page went from 10+MB to ~5MB—it cut my page weight in half!

The moral of the story is don’t “set it and forget it,” especially when adding responsive images using custom code.

Thanks to VIA Studio for their blog post that finally made the solution click for me.

Slanted Background Stripes

Why Eat Your Coffee? page
Sample effect

While working on a recent project, I needed to use angled background stripes on a number of pages.

Here are a couple of requirements that limited my options:

  • Angled stripes with text content and a background color and/or image
  • Angled stripes stacked on top of each other

Continue reading “Slanted Background Stripes”

WooCommerce Downloadable Products: Granting Permissions to Previous Customers

If you’re using WooCommerce to provide downloadable products and add a new download, previous customers do not automatically get access to it as of v3.x.

Here are a couple of options: Continue reading “WooCommerce Downloadable Products: Granting Permissions to Previous Customers”

Post Type Search Form

Adds a shortcode you can use to show a post type-specific search form.

To use, add [post_type_search_form post_type="post_type_here"] where you want the search form to display.

Get the code at the GitHub repository. Continue reading “Post Type Search Form”

How to Use Backblaze B2 with Sermon Manager for WordPress

If you’re hosting a church website on shared webhosting, chances are they limit how much space and bandwidth you can use each month. Uploading sermons each week can eat into those limits very quickly.

Enter Backblaze B2, a cloud storage option costs less than a quarter of what Amazon S3 would cost for the same amount of storage. Backblaze has been around for years as a computer backup solution and has made their name by providing reliable storage at low cost.

In fact, the first 10GB of storage is free, so you might even be able to host your sermons at no cost at all. Continue reading “How to Use Backblaze B2 with Sermon Manager for WordPress”

WPForms: Force Async Scripts

This little plugin has one job: make WPForms’ Google Recaptcha script load asynchronously.

Get the plugin on GitHub.

Installation Instructions

  1. Copy the wpforms-recaptcha-async.php file to your wp-content/plugins/ directory (or compress to a zip file and upload in the WordPress backend “Plugins > Add New”
  2. Activate
  3. That’s it. All the merged scripts will be loaded with the async and defer attributes.

Merge + Minify + Refresh: Force Async Scripts

This little plugin has one job: make all merged scripts produced by the Merge + Minify + Refresh plugin load asynchronously.

Get the plugin on GitHub.

Installation Instructions

  1. Copy the merge-minify-refresh-async.php file to your wp-content/plugins/ directory (or compress to a zip file and upload in the WordPress backend “Plugins > Add New”
  2. Activate
  3. That’s it. All the merged scripts will be loaded with the async attribute.

Potential Issues

Note that if you have plugins or other code that adds inline Javascript, it probably will break if it’s depending on jQuery (for example) to be loaded and active already.

One workaround is to exclude /wp-includes/js/jquery/jquery.js from the Merge + Minify + Refresh cache, but you may have to exclude other scripts as well.