Project Background
A few weeks ago, I went live with a new web project.
It’s called “FLX Squares” – a basic one-page brochure site, mainly intended to promote local square dances in our area.
In my journey as a web designer/developer, it is notable for being my first WordPress site I’ve ever built.
At my old job, I did do some work on the Arcus Foundation website, which was my first time doing any development on the platform.
While I learned a lot, I was merely a minor cog in the that project’s wheel, doing occasional styling work or restructuring a page’s markup or JavaScript here and there.
This project was quite a bit different. I wanted to challenge myself to learn as much about the bones of WordPress theme development as I could, so I felt like there was no other option than to design the site with HTML, CSS, and JavaScript, and then convert that into a working WordPress theme. It was particularly important to me that every single piece of content on the site be dynamic, so I knew I was going to be using Custom Post Types with Advanced Custom Fields.
I know a fully custom theme may not necessarily be the most practical approach for many projects, but it seemed to fit this project’s minimal requirements just fine. These requirements were modest in their scope:
- Modify an existing design (built with HTML, CSS, and JavaScript) to dynamically load WordPress content
- The majority of content on the site should be defined in the WordPress admin. This means using a couple plugins, namely Custom Post Types with Advanced Custom Fields (ACF).
- To start with, use only 2 post types – Homepage section data and Events. The homepage section data entries will have ACF fields for every piece of editable content in any of the sections on the home page. The Events entries will allow content editors (my friends who work on this project with me) and admins (me) to add the details (again, defined as ACF fields) for square dances.
- Keep plugin usage to a minimum. I wanted to do as much of the theme development myself as possible. I also didn’t want to unnecessarily add security vulnerability vectors with unnecessary plugins. Currently, I still only have 3 plugins installed on the site – Custom Post Type UI, Advanced Custom Fields, and Classic Editor.
These barebones requirements, combined with a budget being a non-factor (this project was built pro-bono, out of love and learning) and the minimal design needs, made it a perfect opportunity to build this whole theme from scratch.
Key takeaways
This was intended to be a learning project, so what did I learn?
Well, I’ve made a list of the biggest takeaways for me personally.
- A WordPress theme, as complicated as they can get, can boil down to only two files (in the case of Classic Themes, which is what I built):
index.php
style.css
- Technically, you could have a working theme without
style.css
, but that file contains useful metadata for the theme, so by convention it is found in every single WordPress theme. So I’m classifying it as “required” because not including it could cause unintended consequences. - more PHP files will be added based on the following needs:
- WordPress templating – making use of WordPress’s template hierarchy to render content on pages. Since this is currently a one page website,
index.php
has me covered - PHP templating – like any PHP web project, it’s common practice to abstract reusable snippets like ‘header’ and ‘footer’ into their own PHP files and then render them on any template files like
index.php
,single.php
,custom-page.php
etc. - functions – using
functions.php
as needed to define functions that will be called elsewhere in the theme, like applying stylesheets to the theme, or conditionally rendering a different page<title>
depending on the nature of the requested resource.
- WordPress templating – making use of WordPress’s template hierarchy to render content on pages. Since this is currently a one page website,
- CSS and JavaScript files in your theme are “enqueued”, or loaded in
functions.php
, making that file another crucial one for my theme. (Although admittedly, I am in the habit of writing my JS inside an actual<script>
tag before the</body>
tag, so I actually just created ajavascript.php
file [yes, seeing ‘javascript.php’ gives me a twisted thrill] and rendered it above the</body>
tag infooter.php
. I wound up with two stylesheets for my CSS –theme.css
for the website andadmin.css
for a couple custom styles in the wp-admin dashboard. Note that I kept writing actual styles separate from the unique role ofstyle.css
in the WordPress theme architecture. I think this is a common practice in WordPress theme development from anything I can tell. - In order to actually render the enqueued styles, call the
wp_head()
function in<head>
. - To render the WordPress Admin bar when logged into the site, call the
wp_footer()
function before the closing</body>
tag. - Getting the content into your theme requires the use of PHP
while
loops and calling WordPress functions. (And in my case, functions defined in ACF). I used ChatGPT to get me started with writing this code and modified it to my needs. - One 0f the nice things about working with a platform with as much…legacy…as WordPress is that it is easy to find resources, whether it be with AI or Google search, on whatever topic you’re curious about. I rarely couldn’t find answers to my questions, as long as I knew what I was looking for.
- I wrote more JavaScript than I would have liked.
- One instance was when it came to the more advanced sorting of Events by the event’s datetime value. Basically, I had a PHP loop with logic sorting the events into “Upcoming” or “Past” events based on how their datetime value compares to the value returned by calling
date('m/d/Y')
in PHP. Since that logic was in the same loop as the rendering of the page, I didn’t want to mess with that structure, so I pushed the further ascending/descending sorting logic to the client. I plan to refactor this to instead have two PHP loops for events: one to assign “Upcoming” or “Past” to each event, and then another rendering loop that will contain the other sorting algorithms for ascending and descending based on that value. This will reduce the amount of JavaScript needed by quite a bit and will keep things much cleaner in my opinion. It was surprising how quickly things devolved into unnecessary spaghetti code. While in this case, I don’t think it’s doing much harm, it’s not something I’d want another developer to have to look at or have to tinker with, so that’s enough for me to want to refactor. - I also found myself also writing JavaScript to solve problems that would be better solved in the admin. For example, the logo (which is just html content for the time being) uses a
<span>
tag wrapped around “FLX” to color it. In the case of the Hero section, I defined this content using one field, then manipulated it with JavaScript to wrap the<span>
. This works fine, but its need could be eliminated if I just created a separate field for each word of the logo in the admin. Then I could define all my markup in my PHP files without using JavaScript for this kind of task. - There’s only about 100 or so lines of JavaScript in the whole theme, so it might not matter that much if I don’t get to refactoring the points above. To me, that fact that I could still reduce over 80% of that by refactoring points to just how flexible WordPress is as a platform for the designer/developer. In a marketplace that includes platforms like Squarespace who treat something as simple as a custom JavaScript code block as a premium feature, it’s great to have platforms like WordPress and Shopify (Webflow is close with their CMS feature, but without having a theming system, they don’t make the cut for me in this conversation) with so much more separation of content and appearance, and the amount of flexibility that goes with that.
- One instance was when it came to the more advanced sorting of Events by the event’s datetime value. Basically, I had a PHP loop with logic sorting the events into “Upcoming” or “Past” events based on how their datetime value compares to the value returned by calling
- While it’s in the same category as (and in a lot of ways, outshines) Shopify in terms of simply having its own theming system (I’d like to make this the topic of another blog post), WordPress is behind the eCommerce juggernaut when it comes to developer experience. And it’s not close. The workflow of duplicating a theme for a dev/staging theme instance, deploying/downloading that using the ThemeKit CLI tool, and then clicking “Publish” is one of the best things about working with Shopify. In WordPress, the process is more like:
- use a tool like Local or MAMP, or configure your own Apache server to have a local version of the site
- create Github repo for the theme files only
- once changes are made, commit them and check them into main branch
- copy the theme files that were changed, and paste them into the web host’s file manager for the live WordPress site
This is to say nothing of keeping the data between local, staging, and live sites synced. (Which I gave up on even trying to do, and just lived with having different data in each one.) I understand that in terms of what these two platforms are as products, comparing them can be problematic. One is a free, open-source, 20-year-old blog-based CMS and the other is a premium, paid, specialized eCommerce solution. However, as someone who worked day in and day out for two years on Shopify projects, it’s hard not to miss the developer experience and point out the differences and drawbacks of WordPress. And they are the two most widely used CMS platforms, both with extensible, flexible theming systems, so there is a basis for comparing their DX.
Perhaps the most pertinent takeaway from developing FLX Squares using a 100% custom theme is a less technical one: working with WordPress feels like an everyman’s approach to being a designer/developer. It’s not cutting edge, and it’s not exactly pretty. But by learning to use it, I’m looking at the 43% of all websites powered by WordPress and preparing myself, even just at a basic level, to work on as many of them as I can. In today’s difficult job market for developers, this seems like it can’t be anything other than a valuable choice. I can’t afford to stick to the React/TypeScript meta of more modern frontend technology when I’m simply looking to put food on the table. But it’s honestly both humbling and fun for me to be digging into a 20 year old piece of web tech. It was born at the time when I was kid, discovering the web for the first time and falling absolutely in love with it. So to learn how to wield it and hopefully continue making a living as a developer is a privilege and brings me an intangible sense of joy.