• Studio Code Review

    Studio Code Review

    Lately I’ve been trying out Studio, WordPress’s own local development app. Initially, just as an alternative to Local to see what it could do. I’ve found that Studio Code, the agentic AI built into it, has been surprisingly nice to use. Connected to WordPress-specific documentation, it feels more powerful and reliable than my trial run of that other WordPress experiment, Telex, which tends to unravel with successive requests (in my experience).

    Using Studio Code on a few real-life client tasks this past week, my overall impression is positive: it’s intuitive and I really like being able to connect my IDE to this setup. However, while it’s good at creating a solution it is less good at choosing how a solution should be built in WordPress.

    This is a BETA version, I’m sure the experience will become refined over time and with more usage.

    Make me a theme!

    A human asks a robot to make them a banana, the robots waves a wand to grant their request

    Diving right into Studio Code on the heels of it’s launch (and with 100,000 free AI credits to start), I asked it to build me a new block theme based on an existing classic site, and gave it a full-page screenshot to work from.

    In just a few minutes it had spun up a new site and a custom block theme. “Wow!,” I thought with just a twinge of existential dread, “This is going to save me so much time!”

    But then I looked at how it decided to build. Behind the pretty design curtain was a hardcoded stylesheet of colors, font sizes, spacing values, and core block tweaks that had no global definitions. Rather than using theme.json, or executing designs in core blocks on the page, Studio Code had created something with a classic junior-developer mindset – built literally to the spec but without any consideration for long-term maintainability or natural changes in content over time.

    Taking apart what AI built and putting it back together the “right” way, I wondered if being more specific in my prompts about how to build this theme would improve the result. But also, shouldn’t it already sort of know that hardcoding everything is “wrong”? Or, at least, that it shouldn’t be the default?

    Status:

    • Cost: 100,000 AI credits (0 credits remaining)
    • Level of completion: Incomplete
    • Production-readiness: Not ready*

    *Studio Code is in BETA

    Debugging request

    As I rejiggered the theme, I gave Studio Code a short, specific task to explain why a style wasn’t appearing, using CSS I’d already written and tested elsewhere. I shared the code snippet (add a border-bottom on the current page’s link in the main navigation).

    Studio Code found the relevant code in my theme, checked the frontend and reported that the class it needed — .current-menu-item — wasn’t being applied. Which it then decided to interpret as an error. It called the missing class the “real bug” and promptly dove into architecting a solution.

    As it iterated, showing me a log that proved it was working very hard, it found the reason why the class didn’t exist on the front-end: the nav links weren’t wired to real WordPress Page objects. WordPress only auto-adds .current-menu-item when a nav link references a real post ID. The menu links were hardcoded URLs because Studio Code had created a visual match to my initial design, but not the actual pages indicated.

    But, again, this was a choice made by Studio Code to put placeholder links in the menu rather than create a menu of pages. That’s not something I would do when building a site out and it didn’t occur to me that anyone else (or any agentic presence) would create a menu this way either.

    From this “bug”, it determined that the next step was to create a new PHP function: a filter that manually compared each link’s URL to the current request and tags it as “current” allowing my class to work.

    But that solve was also a totally unnecessary fix (that cost me whole $1.97 in AI credits). The better answer would have been going into the editor and reconnecting each nav item to its actual Page. The new function solved a perceived failure that was actually just WordPress working as intended. If I was using Studio Code as a non-developer, I wouldn’t have known the difference.

    Studio Code didn’t tell me it was about to add a custom function, and it never surfaced that an alternative fix was rebuilding the nav links, not working around their absence. Solving-the-symptom and solving-the-cause looked identical to the tool (because it’s predictive, not consciously trouble-shooting).

    I expected that Studio Code would have the context around how WordPress works to approach the initial request differently. But, that just reinforces the value of my own experience with WordPress over 20 years. I know where to look when funky issues occur. To Studio Code (aka. The Hammer), everything is a nail.

    Status:

    • Investment: 100,000 AI credits
    • Used: 19,727 credits
    • Level of completion: Complete but also wrong
    • Production-readiness: Not ready

    Probabilistic decision-making

    A keen hammer meets a nail in a workshop

    “Combobulating…”

    Part of why I didn’t catch these misdirected efforts in the moment: Studio Code (and other AI pals) display a running log while they work. They are disarmingly busy with file searches, checks, little status lines, and occasional bits of personality. To a human, that reads like someone narrating their process, and we extend that the same trust we’d extend a colleague who’s talking through their steps out loud. A person doing that is usually also self-correcting as they go, so hearing the narration is itself a signal that the work is on track.

    Alas, ’tis but an illusion. The log is a UX pattern, not a transparency window. It tells you the tool is doing something, even when that’s just diving down another rabbit-hole.

    Web designers aren’t out of a job (yet)

    What Studio Code produced worked but it didn’t reliably reach for the WordPress mechanism that would allow for a more functional, thoughtful structure. Like the Mechanical Turk that appeared to play chess autonomously, it’s a fun rush to the finish line but unless you can run through multiple passes and specifically steer it (ouch, the AI credits!), it’s not quite a replacement for the knowledgable human within.

    I can review what Studio Code and AI tools produce and decide whether to accept it or push back on the process. For the parts I need technical help with – building utility plugins and custom blocks – Studio Code is still a genuinely handy tool. I fix what I think it should have done differently, or, as I like to say, make it more better.

    For people who don’t have a background in building websites, or knowledge of what to ask for, what gets produced is likely to create issues: accessibility failures, a plugin or theme that’s hard to maintain over time, and usability problems for anyone else who has to work with what they made.

    In some ways, this reminds me of the evolution of desktop publishing. Once people could create in Microsoft Word, design opened up to everyone. There were fewer barriers to entry – which in my opinion is always good. It also introduced a lot of “bad” design, simply because people weren’t trained in the field. Comic Sans, all caps, off-brand colors, whimsical clip art, centered or fully justified text – these are the classic faux pas that make professional designers cringe. But ugly can be beautiful too. Look at thrift store paintings and found art, both of which have their own dedicated connoisseurs. What’s beautiful is that people want to express themselves, in all kinds of ways. When you don’t know the rules, there are no rules (which is something you also have to discover on your own after you learn all of the rules)!

    So if people want to prompt their way through a website design, that’s not a bad thing. Maybe it becomes a kind of web design renaissance – people generating on the fly and just having fun with it.

    But… as a web developer, there is a place where those rules do matter, when you are making something for public use and not just for your own amusement. So, don’t forget to review the code and push back on those assumptions.


    Resources:

  • Understanding WordPress Section Styles: A Practical Guide

    Understanding WordPress Section Styles: A Practical Guide

    I recently wrote about block variations and block styles, styles associated with a core block that appear when you add a block to your page or post. Common examples are button style variations like “Default,” “Outline,” or other block styles that may be included in your theme.

    Introducing Section Styles

    Section Styles are an extension of block styles and they work with any block that supports inner blocks (groups, columns, covers, etc). The main advantage and use case for Section Styles is that you can create curated design presets for entire “sections” of your pages. And, as with block styles, Section Styles are only loaded when the section exists resulting in better performance.

    Helpful, curated design defaults for everyone

    Section Styles provide helpful defaults and design consistency without limiting the user from making adjustments. Your section style might set heading colors to blue, but users can change individual headings through the block editor without any conflicts. This flexibility works because WordPress keeps CSS specificity low by “using :where() but prefixing it with :root. The result is selectors with 0-1-0 specificity.”

    Section style or pattern?

    Section Styles and Patterns serve different purposes.

    Patterns provide complete content structures: the blocks, placeholder content, and initial layout. They’re great when you want to give users a starting point with a specific content arrangement. With Patterns, we also have the ability to make a design synced or partially synced with pattern overrides.

    Section Styles are more open ended, separating content and style through visual treatments that work across different content structures. They’re especially useful when you want consistent styling options that users can apply to any content they’re building, without dictating the structure.

    For example, you might have a “Feature Section” style that allows for a two-column layout with an image and text. But what if users want that same visual treatment (background color, heading style, button appearance) for a three-column layout? Or a stacked group with a different heading structure? Section styles let them apply visual design presets to any Group, Cover, or Columns block, regardless of what’s inside.

    It’s possible to flesh (section styles) out to include styles for every element and block that WordPress supports, styling them when they are used within this block. It’s for this reason that these types of variations may best be used for container-type blocks, such as Group, Columns, and Cover.

    Justin Tadlock, Styling Sections… (2024)

    Section styles work well when:

    • You want to provide multiple visual options (light background, dark background, accent color) without creating separate patterns for every possible variation
    • Content structures may vary too much to use patterns, but you still want visual consistency
    • Users need flexibility to build their own layouts but don’t want to think about every little design choice
    • You want to update a visual treatment site-wide by editing one file rather than managing pattern instances

    Creating section styles

    Like Global Style Variations or JSON block styles, Section Styles are created in the /styles/ directory at the root of your theme:

    your-theme/
    ├── theme.json
    └── styles/
        ├── spotlight-left.json
        ├── section-contrast.json
        └── hero-banner.json
    

    As of 6.0, WordPress automatically discovers any JSON files in this directory and registers them as available block styles. You don’t need to register them in functions.php or add any PHP code. Note that "version": 3 is required.

    Each file contains a complete style definition. Here’s my working example:

    {
      "$schema": "https://schemas.wp.org/wp/6.9/theme.json",
      "version": 3,
      "title": "Spotlight Left",
      "slug": "spotlight-left",
      "blockTypes": ["core/group", "core/columns"],
      "styles": {
        "color": {
          "background": "var:preset|color|primary",
          "text": "var:preset|color|background"
        },
        "spacing": {
          "padding": {
            "top": "var:preset|spacing|medium",
            "right": "var:preset|spacing|medium",
            "bottom": "var:preset|spacing|medium",
            "left": "var:preset|spacing|medium"
          }
        },
        "elements": {
          "heading": {
            "color": {
              "text": "var:preset|color|secondary"
            }
          }
        }
      }
    }
    

    The filename can be anything, though it’s helpful to prefix with ‘section-‘ for easy identification. Inside your JSON file, the title and slug should match. The title is what users see in the editor, and the slug is the internal identifier.

    Ollie’s theme academy has an excellent how-to video to get you started, Creating a Section Style.

    Unknown unknowns

    I think that there are limitations to what is allowed in Section Style JSON but I’m having a hard time finding specific documentation around this.

    Limitations that I am aware of (not necessarily complete or correct):

    • Section Styles are limited to styles – you can’t add settings here
    • You can style elements per Section Style, but you can’t style a block style variation of an element (ex. Button with the outline style) with the Section Style
    • Each Section Style needs it’s own separate JSON file inside the theme’s /styles/ directory
    • Spacing values DO work but blockGap – for gap spacing – does NOT work
    • Alignment and justification not available here
    • User’s block style adjustments will override the Section Style presets (by design, specificity here is low)
    • Preset values aren’t visible to the user (known issue) – so, even though there may be padding or colors in use, those aren’t displayed in the styles panel

    If you know more, please comment!

    JSON structure and syntax

    WordPress supports shorthand or CSS variables in your section styles:

    CSS variable format:

    "color": {
      "background": "var(--wp--preset--color--primary)"
      }

    Shorthand format:

    "color": { 
      "background": "var:preset|color|primary" 
      }

    The shorthand is a bit easier to read and quicker to edit if you are using presets.

    If you are using the css property to add custom CSS that theme.json doesn’t directly support, you will need to use full CSS (or full CSS variable) inside that string:

    "css": "background-color: var(--wp--preset--color--primary);"
    

    This is because the css property outputs raw CSS to your stylesheet, and WordPress doesn’t process shorthand syntax in these strings.

    Adapting the section style of a parent theme

    Child themes can add new section styles or override parent section styles.

    • To add a new style: Create a file with a unique slug in your child theme’s /styles/ directory. Both the parent’s styles and your new styles will be available.
    • To override a parent style: Create a new JSON file in your /styles/ directory using the same filename, title, and slug as the parent theme. Your child theme version will override the parent’s version entirely.

    Sometimes, when you create a child theme, your custom palette may be applied in unexpected and ungainly ways to parent section styles (patterns as well) and you’ll want to refine these. An override is useful in this case but be aware that you’re completely replacing it, not just modifying parts of it.

    Troubleshooting issues:

    • Mismatched filename and slug when overriding a parent section style
      • I started a new section-primary.json file in my /styles/ folder to override the parent section style. But I forgot to match the title and slug to the parent even through the filename DID match. As a result, neither the parent nor the child section style showed up. Double-check the obvious human errors like naming and syntax (ie. Try turning it off and then on again).
    • JSON syntax errors
      • Missing commas, extra commas, or unclosed brackets will break your entire style file. WordPress can’t parse invalid JSON, so the style simply won’t appear.
    • Incorrect property nesting
      • Some properties need specific nesting structures. For example, heading color must be nested inside a color object:
    // Correct
    "heading": {
      "color": {
        "text": "var:preset|color|secondary"
      }
    }
    
    // Oops!
    "heading": {
      "text": "var:preset|color|secondary"
    }
    

    The theme.json reference on WordPress.org is helpful when you’re not sure about the correct structure for a property.

    Limitations and appropriate control

    The main caveat with section styling is that it is easy to get carried away and add too many style options for group blocks and columns. Here we need to practice restraint to not overwhelm users.

    Carolina Nymark, FullSiteEditing.com

    Section styles should control the container and set sensible defaults for common elements. Content editors should retain full control over the blocks they place inside. If you find yourself writing complex CSS to control every aspect of the inner content, you might be better off with a synced or partially-synced pattern.

    Section Styles are a really cool tool for your Block Theme toolbox. If you’re not using them yet, what are you waiting for?


    Resources

  • WordPress Block Styles and Variations

    WordPress Block Styles and Variations

    When you’re building a WordPress block theme, you’ll often want to customize how a core block looks beyond what the block editor allows. Maybe you want a cover block with diagonal clip-path edges, a featured image that scales on hover, or a fancy Heading style. Before you add a class to that block, consider using a Block Style Variation.

    Benefits of block style variations

    While we could add a class to a block’s “Advanced” settings and style that class under “Advanced CSS” or in a stylesheet, this requires content creators (and you) to remember your class name and how to use it. Block Style Variations are a big improvement, allowing site editors to choose and apply options visually from the block editor’s controls while keeping those styles performant and flexible.

    As a web designer or theme creator, making design decisions easier for site editors is a good thing. Using block style variations also means you can load CSS conditionally (only when the block exists), a performance win.

    How to register styles

    JavaScript, PHP, or JSON

    Styles not shown
    Fig. 1: Block styles aren’t reflected in visual controls.

    I’ll skip the JavaScript (not my job) and look at the PHP and JSON methods.

    Block Variations can be registered via PHP within the theme or in a plugin. If portability of block variations is important to you or if you need to make sure that your block styles are independent from the theme (which could be changed), a plugin approach1 is best.

    Block Styles don’t require registration. They are picked up by WordPress auto-magically when you include the JSON file in your theme’s /styles/ directory.

    One downside with block variations and block styles is that settings don’t appear in the block controls (see Fig. 1).

    If I select a style, like the Button style variation “Outline” – that style change is not reflected in the element style controls2 in the editor even though the attributes exist.

    Wait, aren’t block variations and block styles sort of the same?

    When should I create a block variation vs. a block style? The answer is almost always the same as the answer to another question: Can these changes be made through theme.json styles or CSS? If (theme.json), you should almost always create a custom block style (JSON).

    Block Variations, via WordPress Developer Resources, Theme Handbook

    Block Variations and Block Styles are sort of the same, but also a little bit different. Naming things is hard.

    Consider the problem you are solving: if theme.json supports most of what you want to accomplish and/or if you want a style to be available to more than one core block, the JSON method might work best.

    Carolina Nymark notes that if you want to register Block Styles with a JSON file, “this feature requires WordPress 6.6 and version 3 of theme.json.”

    If you need to do things that mostly aren’t supported in theme.json, like add interactivity with JavaScript or use a lot of custom CSS, use the JavaScript or PHP method to register your block variations.

    Registering block variations with PHP

    Registering block variations3 in your functions.php file makes them available in the block editor’s style panel.

    My example registers four clip-path variations for the Cover block and a scale-on-hover effect for both Cover and Featured Image blocks.

    /**
     * Register block style variations
     */
    function mytheme_register_block_styles() {
        $cover_styles = array(
            'right-clip'     => __( 'Right Clip', 'mytheme' ),
            'bottom-clip'    => __( 'Bottom Clip', 'mytheme' ),
            'left-clip'      => __( 'Left Clip', 'mytheme' ),
            'top-clip'       => __( 'Top Clip', 'mytheme' ),
            'scale-on-hover' => __( 'Scale on Hover', 'mytheme' ),
        );
    
        foreach ( $cover_styles as $name => $label ) {
            register_block_style(
                'core/cover',
                array(
                    'name'  => $name,
                    'label' => $label,
                )
            );
        }
        
        // Featured image variation
        register_block_style(
            'core/post-featured-image',
            array(
                'name'  => 'scale-on-hover',
                'label' => __( 'Scale on Hover', 'mytheme' ),
            )
        );
    }
    add_action( 'init', 'mytheme_register_block_styles' );
    

    The first function is plural, I’m registering several block styles for core/cover at once. I also want to add the “scale-on-hover” variation for the Post Featured Image block and the Cover block.

    Even though I want to use the same style, “scale-on-hover”, for two core blocks – they have to be registered separately in PHP. If I was using the JSON method, I could make a style variation available across blocks using the blockTypes property.

    Both of these block variations use CSS (clip-path, transition, transform) that isn’t supported in theme.json and would require some pretty long CSS strings so the PHP function seems the best approach.

    Organizing CSS files

    Create a /blocks/ directory in your theme to keep blocks and variation styles organized. For this example:

    • assets/css/blocks/cover-variations.css
    • assets/css/blocks/featured-image-variations.css

    You can call the css files anything you want. We’ll reference this file name in the next section when we enqueue our block css.

    TIP: If you just need to add a smidge of CSS (a few lines), you can include the styles directly in the register_block_style() function using the inline_style parameter. There’s a great tutorial by Mike McAlister on Ollie.com that shows you how to do this. Brian Coords has a similar example adding a checkmark variation to the ul element where registering the block style is a separate utility plugin.

    I’ve decided that grouping related variations in a single CSS file makes sense and is more maintainable (for me) but you can also break your styles down into separate stylesheets for each variation, even for the same block.

    Block variations and conditional CSS loading

    This function conditionally enqueues your block variation stylesheets using WordPress’s wp_enqueue_block_style() function, which loads CSS only when the associated block variation is present on the page:

    /**
     * Conditionally load block style CSS
     */
    function mytheme_register_block_style_variations() {
        wp_enqueue_block_style( 'core/cover', array(
            'handle' => 'mytheme-cover-variations',
            'src'    => get_theme_file_uri( 'assets/css/blocks/cover-variations.css' ),
            'path'   => get_theme_file_path( 'assets/css/blocks/cover-variations.css' ),
        ));
        
        wp_enqueue_block_style( 'core/post-featured-image', array(
            'handle' => 'mytheme-featured-image-variations',
            'src'    => get_theme_file_uri( 'assets/css/blocks/featured-image-variations.css' ),
            'path'   => get_theme_file_path( 'assets/css/blocks/featured-image-variations.css' ),
        ));
    }
    add_action( 'after_setup_theme', 'mytheme_register_block_style_variations' );
    

    Use the after_setup_theme to register your Block Variation stylesheets. This makes styles available on the frontend and in the editor.

    Writing the CSS

    In our cover-variations.css file:

    .is-style-right-clip {
        /* Your clip-path styles */
    }
    
    .is-style-bottom-clip {
        /* Your clip-path styles */
    }
    
    .is-style-left-clip {
        /* Your clip-path styles */
    }
    
    .is-style-top-clip {
        /* Your clip-path styles */
    }
    
    .is-style-scale-on-hover .wp-block-cover__image-background {
        transition: transform 0.5s ease;
    }
    
    .is-style-scale-on-hover:hover .wp-block-cover__image-background {
        transform: scale(1.1);
    }
    

    In our featured-image-variations.css file:

    .is-style-scale-on-hover img {
        transition: transform 0.5s ease;
    }
    
    .is-style-scale-on-hover:hover img {
        transform: scale(1.1);
    }
    

    Combining multiple related variations in one CSS file (like my four clip-path variations for the Cover block) will mean that WordPress loads the entire file if any of those variations appear on the page even though they’re not actively used. But this is still a small file and performance impact should be minimal. This is kind of a personal choice, since all of these styles are for the Cover block variations, I don’t mind keeping them together.

    Another way: block styles in JSON

    Originally, /styles/ was used to define Global Style Variations for themes (like a light and dark mode). An advantage of this method is that JSON files within the /styles/ directory are auto-discovered by WordPress (as of 6.0), work across the blocks you specify, and don’t require a PHP function or JavaScript. For this to work:

    “You have to place each custom block style in its own JSON file, or WordPress can not parse them correctly. Place the JSON file inside a folder in your theme called styles, or a subfolder to styles (ex. /styles/blocks/custom-style.json).”

    FullSiteEditing.com, Registering Block Styles using JSON

    If you have a simple block style, like a fancy, visual heading that uses a special font, this could be a good reason to use JSON. You can also tell WordPress that this style can apply to different blockTypes.

    {
      "$schema": "https://schemas.wp.org/wp/6.9/theme.json",
      "version": 3,
      "title": "Shadow Pop",
      "slug": "shadow-pop",
      "blockTypes": ["core/heading", "core/paragraph"],
      "styles": {
        "typography": {
          "fontFamily": "var:preset|font-family|abril-fatface",
          "fontSize": "var:preset|font-size|x-large"
        },
        "css": "text-shadow: -1px 1px 0px #fff, -2px 2px 0px var(--wp--preset--color--secondary);"
      }
    }

    Call this file anything you want, place it in your theme’s /styles/ directory (or a sub-dir of styles) and your style will be available in the editor:

    Block Style Variations,wordpress block style variations
    Magic! The core heading block now has a style variation, “Shadow Pop”.

    How WordPress applies block styles

    When you select a style variation in the block editor, WordPress adds a class to the block in the format .is-style-{variation-name}. For example, selecting the “Right Clip” variation on a Cover block produces this HTML:

    <div class="wp-block-cover is-style-right-clip">
        <!-- Cover block content -->
    </div>
    

    You could use the full block class combined with the variation class (EX: .wp-block-cover.is-style-right-clip) but that’s probably only necessary if you actually run into specificity issues (which is unlikely, I think…).

    WordPress detects your new class on the page and loads the associated stylesheet. If the page doesn’t use any of your style variations, that CSS file isn’t needed and doesn’t load.

    Try block variations and block styles in your theme today!

    Whether you register your block styles via PHP or through the Global Styles, you enhance your WordPress block theme in several ways:

    • Your theme stays lean because variation styles are broken down into small, load-as-needed files rather than one comprehensive stylesheet.
    • Pages now load faster since browsers only download that CSS when blocks are actually present on the page.
    • Users are happy because they can make effortless design changes without being afraid of doing it wrong.

    Maintaining style variations will also be easier for you than remembering where you slapped those ad-hoc classes, wondering if they are still in use, and writing CSS in an external stylesheet or in the dreaded “Advanced CSS” panel.


    Footnotes

    Also see: How to Use Block Variations in WordPress which addresses InnerBlocks.

    Watch on Learn.WordPress.org: Block Style Variations, Intermediate

    1. Register Block Styles via Plugin ↩︎
    2. Known issue, reflect inherited global style values ↩︎
    3. Block Styles in the Block Editor Handbook ↩︎
  • Creating Custom ACF Blocks for WordPress Block Themes

    Creating Custom ACF Blocks for WordPress Block Themes

    But I still need to build custom blocks for clients. As a solo developer working with small businesses, I don’t have the bandwidth (or desire) to learn an entirely new technology stack. With Advanced Custom Fields (ACF) blocks, I can create fully functional custom blocks using the PHP and WordPress templating I already know.

    Advanced Custom Fields (ACF®) is available for free through the WordPress plugin repository but you will need the Pro version to create custom ACF blocks.

    Custom ACF blocks1 combine the flexibility of custom fields with the ease of building out content in the modern block editor interface. No need to write React components or deal with complex JavaScript build processes. Hooray!

    ACF Custom Blocks: In a theme or in a plugin?

    Custom ACF blocks can be plugins or built into your theme. If you are creating a plugin, you just need to register the block from your plugin file instead of functions.php.

    Use a plugin when:

    • The block is site-specific functionality that should persist if you ever switch themes
    • You want to reuse the block across multiple sites
    • The block is complex enough to warrant its own updates and version control

    I prefer to keep it in my theme when:

    • The block is built for that specific theme’s design system
    • It relies on theme-specific styles or CSS custom properties
    • I’m building a custom theme where the blocks are part of the overall design package
    • The client is unlikely to change themes

    For my client work, I usually build blocks as part of the theme. But if I find myself rebuilding the same block type for multiple projects (like an FAQ accordion or a team member grid), that’s when I convert it to a plugin so I can reuse it. You can always move a block from theme to plugin later.

    Setting up your block structure

    With block themes, you should use a block.json metadata file2 rather than registering blocks entirely through PHP. This approach lets WordPress automatically handle asset loading and block registration, which means better performance and less manual code.

    Your block will live in its own directory within your theme. For this example, I’ll walk through creating a text rotation block that cycles through different phrases with a typing animation effect, something a client might use for a dynamic homepage headline.

    For a custom ACF block, you’ll need at minimum two files: a block.json file and a PHP template file.

    • block.json – This is where you define the block’s name, title, description, category, icon3, keywords, and any rendering settings.
    • render.php – You can name this file whatever you want (commonly something like block-name.php or template.php), but you need to reference it correctly in your block.json using the render property. I use the same names for all custom blocks, only the /custom-block-name/ folder changes – I just find it easier to set things up that way.
    • style.css – While you can enqueue styles globally, best practice for performance is to use the style property in block.json to load your block’s stylesheet only when the block is actually used on a page.
    • script.js – You can also add a JavaScript file if your block needs any frontend interactivity.

    Here’s the directory structure I’m creating within my theme:

    /blocks/
      /text-rotate/
        - block.json
        - render.php
        - style.css
        - script.js

    Each custom block – /text-rotate/ in this example – gets its own folder inside of /blocks/ with all its assets contained together. This keeps your theme organized and makes blocks portable if you need to move them to a different theme or turn them into a plugin later.

    Let’s build a custom block

    The block.json configuration

    The block.json file defines your block’s metadata and tells WordPress where to find your assets:

    {
      "$schema": "https://schemas.wp.org/wp/6.9/block.json",
      "apiVersion": 3,
      "name": "acf/text-rotate",
      "title": "Text Rotate",
      "description": "Rotate words on the homepage",
      "style": [ "file:./style.css" ],
      "script": [ "file:./script.js" ],
      "category": "text",
      "icon": "carrot",
      "keywords": ["rotate", "text slide"],
      "acf": {
        "mode": "preview",
        "renderTemplate": "render.php"
      }
    }
    

    You can also extend your ACF blocks by adding Block Supports to your block.json file. This allows editors access to core WordPress block attributes like spacing, alignment, or color.

    Note: ACF Blocks V3 is now available but you have to manually enable this. This version makes the preview mode unnecessary, “…in ACF Blocks Version 3, the concept of modes no longer exists. Rather, your block will always be in “preview”, always showing what’s in your PHP render template in the block preview area. The block’s ACF fields show up in the sidebar, and also in a pop-out sidebar that has more space.”

    Registering the Block

    In your theme’s functions.php, you only need a few lines to register the block:

    function mytheme_register_acf_blocks() {
        register_block_type( __DIR__ . '/blocks/text-rotate' );
    }
    add_action( 'init', 'mytheme_register_acf_blocks' );
    

    The __DIR__ constant points to your theme directory, and WordPress will automatically find and process the block.json file. No need to manually enqueue your CSS and JavaScript, WordPress handles that based on the block.json configuration.

    Creating the ACF field group

    Once your block is registered, create an ACF field group inside of WordPress:

    1. Add a repeater field. I called mine: text_slide
    2. Inside the repeater, add a text sub-field. Mine is: slide_it
    3. Set the location rule to “Block is equal to Text Rotate (sub your block name)”
    Create ACF field group with a repeater field
    Create an ACF field group, add a repeater field.
    Sub-fields for the repeater displayed
    Create your sub-field for the repeater.
    Location rules for your block.
    Set your location rule to the block you registered.

    The render template

    Advanced Custom Fields use PHP templates (server-side rendering) rather than JavaScript for block rendering. This simplifies our workflow and may have some performance and SEO benefits over JavaScript.

    Your render.php file outputs the block’s HTML. This is standard PHP that loops through your ACF fields:

    <?php
    /**
     * Text Rotate Block Template
     */
    
    // Create id attribute allowing for custom "anchor" value
    $id = 'text-rotate-' . $block['id'];
    if ( ! empty($block['anchor'] ) ) {
        $id = $block['anchor'];
    }
    
    // Create class attribute allowing for custom "className" and "align" values
    $classes = 'block-text-rotate';
    if ( ! empty( $block['className'] ) ) {
        $classes .= ' ' . $block['className'];
    }
    if ( ! empty( $block['align'] ) ) {
        $classes .= ' align' . $block['align'];
    }
    ?>
    
    <div id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
        <?php if ( have_rows( 'text_slide' ) ) : ?>
        <h3><span class="headline slide">
            <span>Words hit the page like</span>
            <span class="words-wrapper">
            <?php while ( have_rows( 'text_slide' ) ) : the_row(); ?>
                <i class="is-hidden"><?php echo esc_html( get_sub_field( 'slide_it' ) ); ?></i>
            <?php endwhile; ?>
            </span>.</span></h3>
        <?php else : ?>
            <p>Add some text to see the rotation effect.</p>
        <?php endif; ?>
    </div>
    

    The first part of this template handles block settings that users configure in the block editor’s sidebar. The className and align handling ensures your custom block respects the same settings that core WordPress blocks use.

    WordPress passes these settings to your template in the $block array, which you escape with esc_attr() before output – standard practice for any dynamic data.

    If you (like me) need a starter when working with PHP, the plugin ACF Theme Code is super helpful. There is a free version but it won’t work for repeaters.

    Note: For a deeper explanation of WordPress security best practices, see the ACF security principles.

    Styling the block

    In our render.php template, input words start with the .is-hidden class applied. The CSS and JavaScript will handle revealing and animating them.

    The CSS handles the positioning and visibility states for the rotating text:

    .words-wrapper {
        display: inline-block;
        position: relative;
        min-width: 150px;
    }
    
    .words-wrapper i {
        display: inline-block;
        position: absolute;
        white-space: nowrap;
        left: 0;
        top: 0;
        font-style: normal;
    }
    
    .words-wrapper i.is-visible {
        position: relative;
        opacity: 1;
    }
    
    .words-wrapper i.is-hidden {
        opacity: 0;
        visibility: hidden;
    }
    
    .headline.slide span {
        display: inline-block;
        margin: auto;
    }
    
    .headline.slide .words-wrapper {
        overflow: hidden;
        vertical-align: top;
    }
    
    
    /* Show first word in block editor */
    .editor-styles-wrapper .words-wrapper i:first-child {
    	opacity: 1;
    	visibility: visible;
    }
    

    All the <i> elements are absolutely positioned, stacking on top of each other. Only the visible one uses position: relative, which means only it affects the layout and takes up space.

    I also wanted to be able to see the first word added to my repeater in the editor. Adding a rule that targets the .editor-styles-wrapper and the :first-child does this.

    Let’s improve this CSS by adding an accessibility consideration for the media query prefers-reduced-motion4:

    @media (prefers-reduced-motion: reduce) {
        .words-wrapper i:first-child {
            opacity: 1 !important;
            visibility: visible !important;
            position: relative !important;
        }
        
        .words-wrapper i:not(:first-child) {
            display: none;
        }
    }

    But wait – we hate those bossy !important declarations. How about we instead adjust the CSS specificity by adding the class .is-hidden and .is-visible:

    @media (prefers-reduced-motion: reduce) {
        .words-wrapper i:first-child.is-hidden,
        .words-wrapper i:first-child.is-visible {
            opacity: 1;
            visibility: visible;
            position: relative;
        }
        
        .words-wrapper i:not(:first-child) {
            display: none;
        }
    }

    This targets the first <i> regardless of which class JavaScript applies, matching the specificity without needing to force it with that self-important !important.

    Adding the typing animation

    The JavaScript creates a typing effect where each word types out character by character, pauses briefly, then deletes before moving to the next word:

    document.addEventListener('DOMContentLoaded', function() {
        const headlines = document.querySelectorAll('.headline.slide');
        const typingSpeed = 100;
        const pauseTime = 2000;
        
        headlines.forEach(function(headline) {
            const words = headline.querySelectorAll('.words-wrapper i');
            if (words.length === 0) return;
            
            let currentIndex = 0;
            
            function typeWord(word, text, callback) {
                word.textContent = '';
                word.classList.add('is-visible');
                word.classList.remove('is-hidden');
                
                let charIndex = 0;
                const typeInterval = setInterval(function() {
                    if (charIndex < text.length) {
                        word.textContent += text.charAt(charIndex);
                        charIndex++;
                    } else {
                        clearInterval(typeInterval);
                        if (callback) setTimeout(callback, pauseTime);
                    }
                }, typingSpeed);
            }
            
            function deleteWord(word, callback) {
                const deleteInterval = setInterval(function() {
                    const currentText = word.textContent;
                    if (currentText.length > 0) {
                        word.textContent = currentText.slice(0, -1);
                    } else {
                        clearInterval(deleteInterval);
                        word.classList.remove('is-visible');
                        word.classList.add('is-hidden');
                        if (callback) callback();
                    }
                }, typingSpeed / 2);
            }
            
            function animateNext() {
                const currentWord = words[currentIndex];
                const originalText = currentWord.getAttribute('data-text') || currentWord.textContent.trim();
                
                // Store original text so we can retype it on each loop
                if (!currentWord.hasAttribute('data-text')) {
                    currentWord.setAttribute('data-text', originalText);
                }
                
                typeWord(currentWord, originalText, function() {
                    deleteWord(currentWord, function() {
                        currentIndex = (currentIndex + 1) % words.length;
                        animateNext();
                    });
                });
            }
            
            animateNext();
        });
    });
    

    The script stores the original text in a data-text attribute so it can be retyped on each loop iteration. The intervals are properly cleared to avoid memory leaks, and the modulo operator5 (%) wraps the index back to zero, ensuring the animation loops back to the first word after reaching the end.

    Mistakes were made (learning is doing)

    A few things tripped me up when building this ACF block:

    • Forgetting the file:./ prefix in block.json will cause WordPress to look for your assets in the wrong location. Always use the relative path prefix.
    • Not using block.json at all and trying to register everything in PHP. While this might work in classic themes, block themes expect the metadata file for proper asset handling.
    • Not clearing intervals in JavaScript animations. Always use clearInterval() to prevent memory leaks, especially in animations that run continuously.
    • Using Claude.ai for help: I did have to push back on Claude to reduce complexity. Providing guidance to AI before you start building anything is a good idea: don’t add complexity, check for accessibility, security and performance, avoid !important declarations, etc.

    Troubleshooting common issues

    Asset Loading Issues – CSS and JavaScript files loading on every page instead of only when the block is actually used. If you’re manually enqueuing assets in functions.php, they load globally. Use the style and script properties in block.json instead – WordPress will only load those files on pages where the block appears.

    Block Preview Not Updating – Sometimes you make changes to your ACF fields or template, but the block preview in the editor doesn’t reflect them. This is usually a caching issue. Save the page, refresh the editor, or temporarily change the block’s mode from “preview” to “edit” in your block.json to force a refresh.

    Field Group Not Connected – Your block won’t show any fields if the ACF field group isn’t properly assigned to it. In your field group settings, make sure the location rule is set to “Block” and matches your block’s name exactly (like acf/text-rotate). If you rename your block, you need to update the field group location too.

    File Path Problems – Using relative paths incorrectly is a quick way to break things. In block.json, paths to your CSS and JavaScript files need the file: prefix and should be relative to the block.json file itself (like "style": ["file:./style.css"]). However, if you’re using ACF’s renderTemplate property, it’s just the filename.

    Missing Escaping – Any time you’re outputting ACF field data or block attributes, escape it. Use esc_html() for text content, esc_attr() for HTML attributes, and esc_url() for URLs. Skipping this creates security vulnerabilities, especially if clients can input the data.

    Block Not Appearing in Inserter – If your block doesn’t show up when you try to add it, check your block.json syntax. Also make sure your theme is actually registering the block directory. Remember, you need code in functions.php to tell WordPress where to find your blocks.

    Benefits of the custom block approach for client projects

    The combination of ACF’s visual field builder with block theme architecture gives you something powerful: blocks that are easy for clients to use but give you complete control over markup and styling.

    For solo consultants working with small businesses, this is a big deal. You’re not just building the site, you’re building something clients can manage and maybe even enjoy working with!

    1. The ACF Pro version is necessary to create ACF Blocks ↩︎
    2. Advanced Custom Fields, Block Development ↩︎
    3. The easiest way to add icons to your custom block is with Dashicons ↩︎
    4. prefer-reduced-motion media query on MDN ↩︎
    5. What is modulo?, explainer video on YouTube ↩︎

    Resources:

  • Block Theme Development, Part 2: Page Templates and Custom Styles

    Block Theme Development, Part 2: Page Templates and Custom Styles

    In the first part of this block theme exploration, I looked at getting started with block theme development using the Create Block Theme plugin. This post picks up where we left off, focusing on building out page templates, enabling custom functionality through functions.php, and making custom style adjustments that can’t quite be handled in the site editor styles.

    Setting up page template structure

    Reviewing my template needs, the site requires two main page templates: one with a featured image and page title hero pattern and another for special pages like the homepage. Custom archive views are also necessary for specific category archive views and custom post types. I will need a single view for some of those with the ability to include custom blocks and ACF content.

    The parent theme I’m using (Greyd) has with two basic templates for page content: “Pages” (the default) and “Page with Title.” But, because the default “Pages” template doesn’t have a page title at all, I needed to swap how these templates function.

    Note: Your page title is an H1

    Example of the title block showing the H1 setting

    When I added the title block to my page template in the previous post, I noticed it was an H2. That’s appropriate for post titles in loops, but for the main page title, it needs to be an H1 for proper heading hierarchy and accessibility. The fix was straightforward in the block editor. Opening up my page template, I selected the Post Title block and changed the heading level to H1 in the block settings.

    There should only ever be one H1 heading on your page and this should be your page title. Headings do have a minor SEO value but their semantic function is more important: headings help organize your content and your H1 heading describes the main content on your page. Don’t use more than one H1 per page (even if everyone else is doing it).

    Learning something new about spacing and layout behavior

    Watch me learn something new – exploring block spacing settings.

    Spacing in block themes can be confusing because there are multiple systems working simultaneously:

    • Block padding and margin: can be applied to individual blocks
    • Block spacing: controls the gap between blocks within a group
    • Layout spacing: a global settings that describes how inner blocks are spaced within a group or container

    Go with the flow…

    Working in the editor, I want to try to exert the least amount of control and get it to do the thing because it just feels more stable that way. If I have to futz around with design elements, that just becomes tedious.

    Me

    With block-level dimension settings, we can add all kinds of margin and padding and spacer blocks (still!) to effect a specific layout. However, I see a lot of developers and clients get stuck over-engineering a design solution. If you feel like you are fighting with block styles, take a deep breath and consider how flex and grid containers want to operate. Rather than applying lots of manual margin or padding adjustments to force a specific result, maybe you need to try a different block, or inspect the front-end to understand what is actually happening. Manual block-by-block adjustments are less maintainable and much more tedious to create.

    To better understand spacing in WordPress, we can first take a look at the CSS Box Model. This describes how browsers will calculate space around every HTML element. Each element is in a “box” with four layers (from inside to outside). This is a conceptual box, not a visible box, but if you inspect your code you will see how margin, padding and gap spacing are highlighted within a “boxed” element or layout.

    1. Content – the actual content inside your element box (EX: this could be a paragraph, heading, image, or a group)
    2. Padding – space between the content and the edge of the box
    3. Margin – space outside the border that separates this element from others
    4. Gap spacing – the CSS gap property creates space between flex or grid elements

    How spacing works in WordPress:

    • Padding expands the element itself (background colors and borders extend through the padding area)
    • Margin creates empty space between elements (background colors and borders do not extend into margin)
    • TIL– Block spacing in WordPress is not exactly the same as gap spacing. Block spacing adds space between child elements within a flex or grid container (gap spacing) AS WELL AS adding an equal amount of margin to the top of any default block-level elements inside the container (like a paragraph block).
      • If a container is display: flex; – like the Columns block – the block spacing control changes the default gap spacing between columns.
      • If an element is display: block; – like a paragraph – it will get the same amount of spacing as margin-block-start: var(--wp-preset-spacing-value); since gap won’t affect elements that aren’t using flex or grid.

    Block spacing controls are also available to the theme in the site editor under layout settings. The block spacing setting here will determine the space between all of the blocks on all of your templates across the site.

    In WordPress blocks, we’re manipulating these properties through the visual “dimensions” settings panel. Padding and margin affect the space inside and outside a box (or block), respectively. Block spacing affects the gaps between elements within that group or container block (group, columns, grid, cover block) and the margin-block-start for elements within those containers.

    Thinking about it now, this does seem the most logical way to handle space equity among things that may have a different display modes – but it was not immediately obvious to me. I’m sure its documented, one of my fatal flaws is that I never read instructions first.

    Learn more about spacing settings:

    Adding breadcrumbs to the header

    Breadcrumbs are added to templates using the Yoast Breadcrumb Block.

    Looking at the current site design, I decided to add breadcrumbs to the Page Title Hero pattern rather than above the page content as it is on the current site. I’m using Yoast Breadcrumbs here but there are other plugins that can do this like SEOPress. The Yoast Breadcrumb block does not have any style options available in the editor so I will need to add some custom styles to a separate stylesheet or in the Advanced CSS panel.

    I also want the breadcrumbs to left-align with other header elements, using the wide alignment shared by the navigation menu. This involves working with flex containers and understanding how the cover block centers its content. The cover block is a flex container that aligns items center by default. This was overriding my attempts to space elements using justify-content: space-between.

    Adjusting the position of elements inside a cover block using custom css.

    After experimenting with height settings and flex properties, I realized I needed to add a custom class to override the default align-items center property. Sometimes blocks can get you most of the way there, but for specific design requirements, you may still need to add custom CSS.

    Learn about flex properties: CSS Flexbox Layout Guide

    Enabling page excerpts with a function

    The design calls for an optional excerpt to appear below the page title in the hero pattern. WordPress doesn’t enable excerpts for pages by default, so I needed to add this functionality.

    There’s no functions.php file included by default in my child theme but I can add one. I just need a basic file to add excerpt support for pages:

    add_action('after_setup_theme', function() {
        add_post_type_support('page', 'excerpt');
    });
    

    After adding this code and reloading the editor, I am able to add excerpts to pages through the page settings panel. I can also use the excerpt block on the Pages template and adjust the visual style in the editor. But – what if a page doesn’t have an excerpt?

    Function tweak: conditional excerpt display

    Having the excerpt field available was only half the solution. I wanted the excerpt to display only if it had been manually created, not auto-generated from page content. The excerpt block doesn’t have a built-in conditional setting for this.

    **
     * Enable excerpt for pages - Only show excerpt if manually created
     */
    function themename_block_filter_excerpt( $excerpt ) {
    	if ( ! has_excerpt() ) {
    		return '';
    	}
    	return $excerpt;
    }
    add_filter( 'get_the_excerpt', 'themename_block_filter_excerpt' );

    I asked Claude.ai for an assist. Initially, it produced an overly complex solution involving PHP template files, which would defeat the purpose of building a block theme. The second option it provided was much simpler: adding a filter to the excerpt content that returns an empty string if no manual excerpt exists.

    The code checks if there’s content in the excerpt field, and only outputs it if content exists. This allows the excerpt to remain an optional element in the page template.

    Working with custom CSS in block themes

    For my next design challenge, I wanted to add a drop shadow to my page title. Since this is text over an image, I want to make sure it’s legible and has good contrast. WordPress has shadow support, but it applies box-shadow (to a block container) not text-shadow. My first instinct was to add this to the style.css file referenced in functions.php but that’s like sledge hammer when I just need a small, block-specific style, say, a tack hammer for this operation.

    A great article to understand using styles in the editor on CSS Tricks.

    In the site editor, each block has an “Advanced > Additional CSS” field where you can add properties directly. Instead of writing a full selector in an external stylesheet, you just add the property and value:

    text-shadow: 0 2px 7px rgba(0,0,0,0.5);
    

    This approach is cleaner for one-off block styles. It keeps the styling close to the block it affects and previews immediately in the editor. Save the external stylesheet for the things that you can’t do in the editor at all.

    Wrapping Up

    This phase of development involved a lot of problem-solving around layout and spacing. Working with a classic theme migration with existing content and styles is a lot more complicated than I had anticipated…

    Key lessons from this session:

    Block themes offer flexibility through the visual interface, but there will still be times you need to reach for functions.php and custom CSS for specific functionality and fine-tuned control.

    • Functions.php in block themes should be minimal and focused on functionality you can’t achieve through theme.json or the block interface.
    • Block-level custom CSS is often preferable to external stylesheets for one-off “utility” styles.
    • Visual interfaces are powerful but have limitations. Understanding when to use theme.json, functions.php, and custom CSS is all part of the fun!

    I’ll try to get back to the archive templates and custom post types next. Since these use a lot of custom fields – I may need to convert these to ACF field groups to blocks that can be used in the editor.

  • WordPress Updates: Why they Matter for Your Website Security

    WordPress Updates: Why they Matter for Your Website Security

    If you’re running a WordPress website for your business, you’ve probably noticed those update notifications that pop up in your dashboard. Maybe you’ve wondered if they’re really necessary, or if you can put them off until next month when things aren’t so busy.

    Keeping your WordPress site updated is one of the most important things you can do to protect your business online. Think of your WordPress site like your office building. You wouldn’t leave the back door unlocked overnight, right? Updates are like changing the locks when someone loses a key, or fixing a window that doesn’t latch properly. When you skip them, you’re leaving points of entry open for anyone who happens to walk by.

    WordPress security updates

    WordPress is open-source software, which means its code is public. This openness is a good thing. It means smart people are constantly checking for problems and suggesting improvements. Because testing and updates are frequent, and so many people are working to address issues, you can argue that open source is more secure than proprietary software, not less.

    When security researchers find a weakness, they report it so it can be fixed. WordPress releases an update to patch that hole. Once that fix becomes public, the weakness also becomes public. Bad actors may start looking for websites that haven’t updated yet to exploit the known security flaw.

    This is why you’ll sometimes see an update come through that WordPress marks as a security release. These updates should be made when released and most hosting companies make them automatically. If you site doesn’t update right away, check the automatic Wordpress update settings allowed on your web hosting account (where these can be found may vary by hosting provider). There is usually an option to allow minor security releases to auto-update. You can also choose to skip the major core version updates and do those manually.

    “But my site works fine, why risk breaking it?”

    This is probably the most common pushback I hear about updates. It makes sense on the surface. If your site is working, why mess with it?

    “Working” and “secure” aren’t the same thing. Your site can look and function just fine while having security holes that won’t be obvious until someone exploits them. By the time you know there’s a problem, the damage is done.

    Your smoke detector batteries might be dead, but you won’t know until there’s a fire. Updates are like testing those batteries monthly. Yes, climbing up on the ladder is a minor hassle. But it’s a lot easier than dealing with a fire.

    The risk of breaking something with an update exists, but it’s unusual unless your working with a lot of customization or plugin updates that may have “breaking changes”. Maintaining backups, and testing those backups, should be part of your update process. The risk of getting hacked because you didn’t update is real and the consequences are much worse and harder to fix.

    Updating WordPress manually: understanding what needs to stay current

    Your WordPress site has several parts that need regular updates:

    • WordPress core is the application. This is the basic software that makes everything run. The WordPress team releases updates regularly, including small maintenance releases and larger feature updates. The security team is particularly active, pay attention to those update notifications in your WordPress dashboard.
    • Your theme controls how your site looks and often adds features specific to your design. If you’re using a theme from a reputable commercial developer, they’ll release updates when WordPress changes in ways that affect themes, or when they find bugs and security issues. Watch out for WordPress themes from outside of the WordPress theme repository – these commercial themes often have plugins bundled within that theme that may also require licenses and updates and can impact the security of your website – Revolution Slider and WP Bakery are common bundled plugins that have had some issues in the past.
    • Plugins add extra functionality. Contact forms, galleries, SEO tools, backup systems, you name it. Support and quality varies widely here. We’ll talk about how to decide what plugins to add to your site in the next section.
    • PHP is the programming language that WordPress runs on. Your web host controls which version of PHP your site uses. This is often overlooked but critically important. Older PHP versions stop receiving security updates, just like old versions of WordPress. WordPress and many plugins will not be backwards compatible with older versions of WordPress – the minimum recommended version is 7.4 but you should try to get the most current, stable version if you can – 8.2 or 8.3 (as of the writing of this post).

    These parts all work together. Sometimes a WordPress core update changes something that affects how themes or plugins work. A responsible theme or plugin developer will test their product with new WordPress versions and release an update if needed. This is why you might see a theme update right after a major WordPress release, the developer is making sure everything stays compatible.

    How to tell if a plugin is still safe to use

    Not all plugins are maintained equally. Some developers abandon their plugins, stop responding to support requests, or just don’t have the bandwidth to maintain an open source plugin. Using an abandoned plugin is like installing a smoke detector with no way to change the batteries.

    • Last updated more than a year ago. Check the plugin’s page in your WordPress dashboard or on WordPress.org. If the last update was over a year ago, be cautious.
    • Not tested with recent WordPress versions. You’ll see a notice like “This plugin hasn’t been tested with the latest 3 major releases of WordPress.” This doesn’t automatically mean it’s broken, but it means the developer might not be actively maintaining it.
    • Lots of unresolved support questions. Look at the plugin’s support forum. If people are reporting problems and getting no response from the developer, that’s a red flag.

    If you’re using a plugin with these warning signs, start looking for a replacement. Don’t wait until it breaks or creates a security problem. Finding and testing a replacement while things are working is much less stressful than doing it in an emergency.

    What could break when you update (and why)

    Updates don’t usually break things, but when they do, it’s helpful to understand what went wrong:

    • Plugin conflicts happen when two plugins try to do something that conflicts with each other, or when a plugin update changes how it interacts with other plugins. This is more common on sites with lots of plugins.
    • Theme incompatibility occurs when WordPress adds new features or changes how things work, and your theme hasn’t been updated to match. This is why theme updates often follow WordPress core updates.
    • Custom code problems are tricky. If someone added custom code to your site (maybe in your theme’s functions file or a custom plugin), that code might rely on WordPress features that changed or were removed. This is the most frustrating type of break because it requires a developer to fix the custom code.
    • The white screen of death is what people call it when your site stops loading entirely and just shows a blank white screen. This usually happens when there’s a fatal PHP error. It sounds scary, but it’s fixable with access to your site’s files.
    • Memory limit issues can show up after updates if the new version of WordPress or a plugin needs more server memory than you have available. Your host can usually increase this.

    Most of these problems can be caught and fixed before they affect your live site if you’re testing updates properly.

    Automatic updates: when they help and when they don’t

    WordPress can update itself automatically. By default, it handles minor updates (like going from version 6.9 to 6.9.1) on its own. You can also enable automatic updates for major versions, themes, and plugins.

    When automatic updates make sense:

    • WordPress minor/security updates (usually safe to automate)
    • Simple sites with well-maintained, popular plugins
    • Sites where you have good backups and monitoring in place

    When to avoid automatic updates:

    • Sites with custom code or themes
    • Sites using plugins that often have compatibility issues
    • Sites where a few hours of downtime would cause serious problems
    • Major WordPress version updates (worth testing first)

    If you enable automatic updates, you still need monitoring. Set up alerts so you know when updates happen, and check your site afterward to make sure everything works.

    Test major core updates and plugin that warn of breaking changes on a staging site first.

    What does it mean to test an update? (staging sites explained)

    When I say “test updates on a staging site,” I mean creating a copy of your site where you can try things out without affecting your live site. This copy is called a staging site or development environment.

    You wouldn’t remodel your store while customers are shopping. You’d close for renovations, or at least work on a section at a time. A staging site is like having a complete copy of your store in a back room where you can test changes before customers see them.

    Many web hosts now include staging environments as part of their hosting plans. You click a button, they create a copy of your site, and you can update and test on that copy. If everything works, you push those changes to your live site. If something breaks, your live site wasn’t affected.

    Staging sites cost different amounts depending on your host. Some hosts include them free, others charge $5-20 extra per month. If your host doesn’t offer staging, a developer can set one up for you, though this may involve additional costs.

    For small business sites, staging is worth it if:

    • You have a complex site with business-critical plugins like WooCommerce
    • You have custom code or an older theme
    • Your site is critical to your business (you can’t afford downtime)
    • You’re several versions behind on updates and need to catch up

    For very simple sites with just a few well-maintained plugins, you might be okay with good backups and manual testing on your live site during off-hours.

    How to make a backup

    Before any update, you need a current backup.

    • Check if your host does automatic backups. Log into your hosting control panel and look for backup settings. Many hosts backup your site daily, but check:
      • How often they run
      • How long they keep them (30 days is good)
      • How to restore them if needed
    • If your host doesn’t backup, use a plugin. Free options like UpdraftPlus or BackWPup can create backups and save them to cloud storage like Google Drive or Dropbox. Install one, configure it to backup both your files and database, and set it to run at least weekly.
    • Test your backups occasionally. A backup you can’t restore is useless. Every few months, try restoring a backup to make sure the process works. Many people find out their backups are broken when they desperately need them.
    • Before updating, create a fresh backup manually. Don’t rely only on automatic backups. Create a new one right before you update, so you have a restore point from minutes ago, not days ago.

    If this all sounds complicated, it’s one of the main things a good maintenance plan handles for you.

    What to do when you can’t make an update

    Sometimes you’re stuck. Maybe a plugin update won’t work with your hosts PHP version or you have a custom coded site that might not be compatible with a major core release.

    • Make a plan to fix it. If you can’t update now, when can you? Put money in the budget for next quarter to rebuild that custom feature properly, or to migrate to a modern theme. Don’t let “I can’t update right now” turn into “I haven’t updated in three years.”
    • Consider a rebuild. Sometimes starting fresh costs less than trying to update a very old site. If your site is 5+ years old with an outdated theme and abandoned plugins, rebuilding with modern tools might be smarter than patching holes forever.

    Make sure you have some other security measures in place:

    • Use a web application firewall. Services like Cloudflare or Sucuri can block many attacks before they reach your site. This isn’t a substitute for updating, but it adds a layer of protection.
    • Lock down your login page. Use a security plugin to limit login attempts, require strong passwords, and enable two-factor authentication. Most attacks start by trying to guess your password. While we’re here, please use a password manager and don’t reuse your passwords.
    • Monitor activity. Use a service that watches for changes to your files or signs of compromise. The faster you catch a problem, the less damage it does.

    What to look for in a maintenance plan

    If you’re hiring someone to handle updates, a good maintenance plan should include:

    • Regular update schedule, not just when something breaks. Most professionals update sites weekly or bi-weekly for plugins and themes, and within 24-48 hours for WordPress security releases.
    • Testing before updates go live. Your maintenance provider should have a staging copy of your site where they can make sure the update doesn’t break anything. A good provider won’t just click “update all” and hope for the best.
    • Backups before changes. If an update does cause a problem, you want to be able to roll back to exactly how things were before.
    • Monitoring after updates. Sometimes problems don’t show up immediately. Your maintenance provider should check that your forms still work, your pages still load, and nothing looks broken.
    • Clear communication. You should get reports on what was updated and whether any issues came up. Radio silence isn’t good customer service.

    Ask potential providers these questions:

    • What happens if an update breaks something?
    • How quickly will you respond if my site goes down?
    • Do you test updates in staging first?
    • What’s included in your monitoring?
    • How do you handle PHP version updates?

    Warning signs: If someone offers maintenance for $10 a month, they’re probably just running automatic updates without testing or monitoring. If they can’t explain their process clearly, or if they say updates aren’t that important, find someone else.

    When updates are urgent (and when you have time)

    Not every update needs to happen immediately. A plugin that adds a new feature or fixes a minor display issue can usually wait a few days while you make sure the update won’t cause problems with your specific setup.

    Immediate updates recommended for:

    • WordPress security releases
    • Plugin updates marked as fixing security issues
    • Updates that patch actively exploited vulnerabilities (WordFence and PatchStack maintain a WordPress vulnerability database you can subscribe to.)

    Update within a week or two for:

    • WordPress major version releases
    • Theme updates (unless your theme is highly customized)
    • Plugin updates from reputable developers

    Can probably wait a bit, but don’t forget:

    • Feature additions
    • Minor bug fixes
    • Performance improvements

    The danger in waiting is that updates pile up. If you skip a few rounds, you might find yourself several versions behind. At that point, updating becomes riskier because you’re making bigger changes all at once. It’s easier to update from version 1.2 to 1.3 than to jump from 1.2 to 2.0.

    Taking action with less stress

    If you’re managing your own site, start small. Set aside 30 minutes once a week to log into your WordPress dashboard and check for updates. If you see a security update, make it happen that day. For other updates, you can take a bit more time to research if other users are reporting problems, but don’t let things pile up.

    Before you update anything, make sure you have a current backup. Check that your host’s backups are running, or set up a backup plugin if they’re not.

    If this sounds like too much extra work, hire a professional. Your time is valuable, and maintaining a website isn’t your main job. Finding a reliable professional to handle updates is usually less expensive than you’d think, often $50-100 per month depending on your site’s complexity, and far less expensive than recovering from a hack.

    Your website is often the first thing potential clients see when they look for your business. People judge your credibility partly on whether your site works well and looks professional. A hacked or broken site sends exactly the wrong message. Keeping WordPress updated is the simplest way to protect that investment.

    Resources:

  • Block Theme Development: Migrating a WordPress Classic Theme, Part 1

    Block Theme Development: Migrating a WordPress Classic Theme, Part 1

    Even two years ago, I wasn’t completely confident that I could create everything needed in a block theme for a custom business website. Last year, I reversed my opinion: block themes are now a solid solution for even very complex sites. I don’t grasp all the complexity around Node.js development tools but I no longer feel that they are a prerequisite. With Advanced Custom Fields (Pro), and a good understanding of how the parts of a block theme work, great strides can be made.

    I’ve been itching to migrate one particular legacy site over to a block theme to see just how great an impact to site performance there is. I’m also keen to spread the joy of blocks to clients. I anticipate that there will be an improvement to site usability and a confidence boost for content publishers with a block theme.

    First question: Can/should I even attempt this?

    Built in 2018 using Underscores (_S), this is one of my first fully custom PHP themes as a freelancer. The current website received an interim hybrid update in 2019 to take advantage of some block styles and settings – but not all settings are available so it’s hard to visualize how changes will actually look when published.

    Before taking this site apart, I need to make sure critical functionality wouldn’t break. This particular site connects to a third-party chamber of commerce management tool and relies on some scripts and a template file to work. If I do need a PHP template down the road, I can still add that in the new block theme.

    But there are some issues I know I have to tackle:

    The site has extensive design customizations including animated text, hover effects, custom drop shadows, shapes, and icons. All of this will require custom styles that are beyond what the current site editor can generate. There’s also some content sprawl and complex navigation, but I think I will ignore this until I get past the design work and have a base theme in place (note to self: content work is out of scope, even though it begs for a gentle tidy).

    There are several custom post types with overwrought PHP templates and lots of custom fields. I am hopeful these will be easier to manage visually in a block theme – we shall see!

    Catalog the current site needs

    The current site uses the Custom Post Type UI plugin to create five post types and custom taxonomies for each. These are easy to migrate to Advanced Custom Fields, which I want to do. ACF Pro lets me manage all my post types, taxonomies, and fields in one place. I might also use it to create some custom blocks, like for the text animation currently on the homepage which is already using custom fields.

    Choosing a block theme: Start from scratch or use a parent theme?

    Since most design and layout work happens with blocks on a page, I first need to decide whether starting with a premade theme is even necessary.

    Rolling your own means you only build what you need. You don’t end up with templates and patterns for every possible scenario. But if you code from scratch, you have to manually update your theme.json whenever WordPress makes new block settings or styles available (that you may want access to).

    So, in developer-speak: it depends. Understand what you want to accomplish first. There are pros and cons with each approach.

    The minimum requirement to enable a block theme is a style.css, theme.json, and templates/index.html file. You don’t need any content here except for theme.json where you want to create a valid JSON object with schema reference and version number. Toss that in a folder, zip it up and upload to your site – start designing with the site editor! But, you can’t do everything in the site editor (yet). Enabling some of the settings and styles available to core blocks through theme.json will require some manual editing of that file.

    Using a ready-made theme means you’ll get a head start with some useful presets and you get updates when the theme is updated – so choosing a well supported block theme or parent theme is very important. The downside is you will probably get a lot of templates and patterns you don’t actually need in the theme (I call these “patterns for all occasions”). Patterns may be helpful for non-designers to get a quick start on layout. Since I’m doing a custom design, I don’t find them particularly inspirational – and sometimes patterns in themes have weird structure like an overabundance of divs or vestigial spacer blocks.

    I do like Twenty Twenty-Five. Very robust, but equally complex, this is a great choice for a simple site that needs adjustments you can do in the editor alone. With the extensive style customizations I need to do, it feels like I’ll have to fight with it too much.

    My fallback theme favorite is Greyd from Greyd Suite. It’s not too opinionated, has excellent accessibility features built in (hello, great focus states), I know it’s getting solid support, and it feels more flexible than most “designed” themes. Ollie and some others are also popular and good options, but the design of these are too controlled for my taste.

    Setting up the theme

    I’m choosing to create a child theme of Greyd because I feel like it might give me a little speed in development.

    To add my own custom fonts and color palettes, the Create Block Theme plugin makes everything easy.

    First, I use Create Block Theme to generate my child. Next, I update my color palette and custom fonts in the child. When I write these changes to my child theme, I make sure to uncheck “write patterns” so I don’t end up with a bunch of patterns I don’t need synced within my theme. This save generates a new theme.json file with my customizations.

    Next, I wanted to set up in the two main patterns: the header and the footer. In Greyd, there are multiple design patterns available, but to make my life easier, I just want to customize the Header and Footer defaults. That way, I don’t have to go back and update header and footer patterns on every single template. Default patterns are included, well, by default.

    Hot Tip: Try to find the simplest solution to a problem before reaching for complexity.

    Tackling the home page

    The home page is almost entirely driven by custom fields, so I could have easily gotten stuck here. Instead, I decided to just sketch it in and come back to it later. I created the hero section with a featured call to action pattern and moved on.

    When things stop working for no obvious reason

    In the current design, images have drop shadows. This should be easy with the shadow style for images, right? For some reason it worked on standalone images but not on featured images in post loops. I could see the shadow in the editor but not on the frontend.

    This is typical – you start with a fresh new site, the future is bright, and then things start going wrong. These things are universally true:

    1. Your assumptions will be challenged
    2. You will have to troubleshoot things that appear “broken”
    3. You will have to troubleshoot your troubleshooting
    4. You probably have a syntax error

    I opened my theme.json file in my IDE (I use PHPStorm if you care about those things) and manually added the shadow presets to see if they’d get picked up. That worked for the image block but still not for post featured images in a query loop. This was a clue that the setting probably needed to be enabled for that specific core block under styles in theme.json.

    Important note about editing theme.json

    After saving external edits to a theme.json file, you have to go to the site editor and reload the page. This has to be an editor or template page, not just a regular WordPress page. Reloading updates the database, which updates the version of theme.json stored there, with your manual edits.

    If you don’t do this and you keep making changes in the editor, your next “write to theme” command will make the site editor’s version of theme.json the version of record and your manual edits will be overwritten.

    Note that this kind of back and forth between your IDE and the editor is really only workable at the beginning of a project. Over time it gets messy. My advice is to get your theme.json set up with the basics it needs, then work on styles in the editor – and use your style.css file if needed.

    When the “Advanced CSS” editor doesn’t cut it

    We’ll look at this more in future posts but you may need to use your style.css file if you’re doing fancy things like CSS animations, pseudo effects, or … trying to adjust link and focus styles. These can’t (yet) be managed through the editor.

    Next time: Archive Views

    I could sense I was about to get stuck on some more complex functionality on the home page, so I decided to take a break and move on to some other big pieces, like archive views.

    And that’s where I’m leaving things for part 1.

    Read the next part in this series where I discover something new about block spacing and more!


    Resources to learn more about block themes:

  • Using Additional CSS in WordPress Block Themes

    Using Additional CSS in WordPress Block Themes

    The great advantage of working with block themes vs. classic themes is that you can build your designs visually through the WordPress site editor. However, there are times when WordPress meets a simple design need (for example, adding ::before and ::after quote marks to a blockquote) and makes a mountain of a molehill.

    One helping tool here is the slightly obscure ability to add custom CSS directly to individual blocks via Additional CSS. While there are multiple places to include custom CSS in WordPress – adding a class to a block, using a separate stylesheet, or using the Customizer’s Additional CSS section – the block-level Additional CSS feature gives us a precision tool for specific block enhancements.

    Who and what is Additional CSS for?

    The Additional CSS feature in the WordPress block editor is designed for users with basic CSS knowledge who wish to customize a block appearance through the site editor, without modifying theme files. It replaces the CSS “customizer” feature in classic themes (although you can still access this if you really want to, at /wp-admin/customize.php).

    The Additional CSS feature is mostly for manual overrides or one-off changes that the block editor and/or theme.json don’t support right now. Unlike theme customizations that affect your entire site, block-level CSS targets only the selected block instance, meaning it is only used when the block exists on a page or post.

    Highlights:

    1. No main selector needed in Additional CSS for blocks – WordPress applies your CSS to the selected block automatically
    2. Use & for pseudo-elements and nested selectors – Use for targeting ::before, ::after, and child elements
    3. Media queries may not work reliably (in my test) – Use theme-level CSS for responsive adjustments
    4. Consider CSS functions – clamp(), min(), and max() can provide responsive behavior without media queries

    Why use block-scoped CSS?

    Using Additional CSS within a block offers several advantages over site-wide styling:

    • Content-specific design: Useful for quick, one-off design tweaks that don’t warrant a new block variation or a section style.
    • Safe experimentation: Test styling changes. Block-scoped CSS won’t break existing designs or affect other pages.
    • Performance optimization: Styles only load when the specific block type is present on a page, reducing unnecessary CSS overhead compared to loading all possible block styles globally.

    For a more in-depth look at adding CSS and JavaScript to WordPress blocks, check out Brian Coords video on that topic.

    How to find the additional CSS feature in WordPress

    The Additional CSS option is located in the block editor but isn’t immediately visible.

    Finding Additional CSS under “Advanced” in the style editor.
    1. Open the WordPress site editor (Appearance > Editor)
    2. Select any block in your template or design Look for the block settings panel on the right side of your screen
    3. Scroll down to find the “Advanced” section
    4. Click to expand the “Advanced” dropdown
    5. You’ll see an “Additional CSS” textarea

    The textarea is where you’ll write your custom CSS code for that specific block.

    Aside: I’ll speak for all web designers and say we kinda hate how Additional CSS stuffs our programming language of choice into an obscure, hard to find box with no code formatting.

    How to write CSS for individual blocks

    The description for this tool tripped me up initially: “Add your own CSS to customize the appearance of the [specific] block. You do not need to include a CSS selector, just add the property and value.” There should be a link to a resource that has more detail here since, usually, if we want to add custom CSS, it’s because we want to do something more complex with nested styles and not just modify a base default.

    The point is, don’t use a selector for the main block. WordPress automatically applies your styles to the selected block.

    For example, if you want to style a blockquote, instead of writing:

    /* this won't work */
    .wp-block-quote {
        color: red;
    }
    

    You write:

    /* yay! your quote is now a brilliant red color */
    color: red;
    

    Working with pseudo-elements and nested selectors

    For pseudo-elements like ::before and ::after, or to target child elements, use the & symbol to reference the current block and parent selector:

    color: red;
    quotes: "\201C""\201D""\2018""\2019";
    
    &::before {
        content: '\201C';
    }
    
    & :where(p:last-of-type)::after {
        content: '\201D';
    }
    
    & :where(cite) {
        border-top: 1px solid #BEBEC0;
    }
    

    The & symbol is a preprocessor feature (from Sass/SCSS and Less) rather than standard CSS, and WordPress’s block editor processes this syntax for us.

    • Pseudo-elements (&::before, &::after)
    • Pseudo-classes (&:hover, &:focus)
    • Nested selectors (& p, & .custom-class)

    The media query fumble

    I assumed that I could add responsive behavior to a block as well like this:

    border: 0 !important;
    position: relative;
    margin-block: 1.5rem;
    
    &::before {
        content: '\201C';
        top: -1.75rem;
        left: -1.25rem;
    }
    
    @media (max-width: 768px) {
        &::before {
            top: -2.55rem;
            left: .55rem;
        }
    }
    

    But, I was wrong. Although media queries are supported in the block editor, there may be some nuances and occasional issues where media queries behave inconsistently.

    For now, if media queries inside block-level Additional CSS don’t behave as expected, it’s recommended to add those styles globally (in the theme Additional CSS or stylesheets) until native support is added.

    Split the difference

    After discovering this limitation, here’s the working approach:

    Block Additional CSS (for base styles):

    border: 0 !important;
    quotes: "\201C""\201D""\2018""\2019";
    position: relative;
    margin-block: 1.5rem;
    
    &::before {
        content: '\201C';
        font-size: min(max(4rem, 5vw), 8rem);
        font-family: Georgia, Times New Roman, Serif;
        color: #4271d750;
        position: absolute;
        top: -1.75rem;
        left: -1.25rem;
    }
    
    // add the closing quote mark after the last paragrph
    & :where(p:last-of-type)::after { 
        content: '\201D';
    }
    

    Use the global theme Additional CSS (Appearance > Customize > Additional CSS):

    @media (max-width: 768px) {
        .wp-block-quote::before {
            top: -2.55rem;
            left: .55rem;
        }
    }
    

    Where does additional CSS go when changes are saved?

    Additional CSS added through the block editor – such as custom classes specified for individual blocks – is saved in the block’s attributes within the WordPress database.

    The actual CSS code that styles these custom classes is not written to theme.json unless you manually include it OR use a helpful plugin like Create Block Theme to write changes to the theme.

    The site editor now shows a version history of style changes made on the fly in the editor, allowing us to restore to a previous version if we make a mess of things.

    Should you use Additional CSS in a block or in a theme?

    I would think of Additional CSS as utility CSS, reserved for temporary or minimal style tweaks that don’t call for a new block variation.

    Block Additional CSS

    • Simple positioning and layout
    • Pseudo-elements and basic interactions
    • Other block-specific customizations

    Theme Additional CSS

    • Media queries and responsive behavior
    • Complex selectors that target multiple blocks
    • Global styling rules

    Block Theme refresher

    If you are building custom block themes I recommend looking into Full Site Editing from Carolina Nymark, the Block Theme Academy, now FREE and hosted by Mike McAlister at Ollie.com, and learn.wordpress.org.

    Minimal ingredients to create a block theme

    A block theme needs the style.css, index.html, and theme.json files to be fully functional.

    • theme.json: Manage global and block-level styles and settings for a theme
    • style.css: Needed to register your theme. The only required part of the file header is the theme name.
    • index.php: This is your default page template using HTML with block markup.
    Added features and functionality
    • Block variations: Create predefined style variations for blocks that can be selected by the user
    • Block patterns: Pre-designed block combinations that users can insert as starting points
    • Section styles: A built-in styling system for grouping and organizing blocks with consistent design patterns – kind of like a cross between a template part and a pattern
    • Custom blocks: When core WordPress blocks don’t meet specific functionality needs, you can create entirely new blocks with unique features, custom fields, or specialized layouts
    • Other stylesheets: Organize custom CSS in separate files (but still try to rely on defaults within theme.json, good design needs limitations after all)
    • functions.php: Not required for block themes, but you can include it for extra PHP functionality (e.g., registering block patterns or styles).

    Without learning about how and why the site editor works the way it does, you’ll find it much harder to adapt a classic theme development approach to the block editor. Block themes can be incredibly flexible, but they do require a shift in approach.

    Many ways to design and build

    There’s no single way to do block themes “right” and you don’t have to employ a complex build process (I don’t). Start anywhere and experiment.

    Additional CSS at the block level works well for styling specific blocks across your site without editing theme files. It’s ideal for making one-off changes to a core block appearance (like all quote blocks or all button blocks) that you can’t yet accomplish in theme.json or in the style editor. Scoping CSS to a specific block avoids generating monstrous global theme CSS since those styles will only be inlined if the block exists on a rendered page.

    Have questions or thoughts? Please share your comments below!

  • Self-hosting variable fonts with WordPress

    Self-hosting variable fonts with WordPress

    Pick Your Dev Method: Block, Hybrid, or Classic?

    How you self-host fonts depends entirely on the type of WordPress theme you’re building. If you are creating a Block Theme – great news! You don’t have to read this article! WordPress now lets you add and manage custom fonts directly in the Site Editor under Styles → Typography.

    However, if you’re working with a Hybrid Theme or a Classic Theme, you’ll need to do a little more hands-on work:

    • Download your fonts
    • Convert .TTF font files to .WOFF2 files
    • Load them cleanly through functions.php and theme.json

    However you decide to build your theme (or non-WordPress website), you will want to make sure that you are optimizing the technical aspects of the site as well as it’s content. Including external fonts locally, within your theme, is an easy win.

    Why is it important to self-host fonts?

    • Faster page loads
    • Better Core Web Vitals
    • Full control over privacy and design

    Say Hello to Variable Fonts

    Variable fonts allow for greater design control with optimized performance. Using a single, variable font file we can use CSS to adjust properties like font-stretch, font-style, and font-weight. But, including variable fonts can be a little tricky. If you’ve downloaded .ttf files for a variable font from Google Fonts and have gotten stuck because it’s not rendering correctly, it’s not just you. The devil is (so often) in the details.

    In this example, I’m using a Hybrid Theme approach. Let’s walk through exactly how to self-host variable Google Fonts correctly — and how to fully support Gutenberg editor styles too.

    Why .TTF Fonts Aren’t The Best Choice for the Web

    First, .ttf (TrueType) fonts were never designed for the web:

    • They’re huge compared to .woff2 (30–50% bigger).
    • They don’t stream efficiently, slowing down first paint.
    • They carry extra metadata browsers don’t need.

    Modern browsers love .woff2 because it’s lightweight and streamable. If you want fast fonts, you must convert your .ttf files.

    How to Convert .TTF Files to .WOFF2

    After testing several tools, the best converter I tried was Everything Fonts TTF to WOFF2 tool. It delivered clean, minimal .woff2 files — no bloated metadata, no weird rendering issues.

    💡 Pro Tip:
    Make sure you’re converting variable .ttf files if you want full weight ranges (100–900), not just individual weights. While you can convert any .ttf font file, if it is not a true variable font, you won’t get all of the benefits. This process will not magically create a variable font for you.

    Setting Up Local Font Hosting in Your WordPress Theme

    You’ve selected the variable fonts that you want to use and you’ve download the files. Next, you’ll want to convert the .ttf files to .woff2 files, as mentioned above. I’ll be using REM and Nunito, both variable Google Fonts in this example. Here’s how you can now include your fonts in your WordPress theme:

    1. Organize Your Fonts in Your Theme Folder

    Store your converted fonts neatly inside your theme:

    /assets/fonts/nunito/Nunito-VariableFont_wght.woff2
    /assets/fonts/rem/REM-VariableFont_wght.woff2
    

    ✅ One folder per font family keeps things clear and maintainable.

    2. Create a Fonts CSS File

    Create an /assets/css/fonts.css with proper @font-face declarations:

    @font-face {
        font-family: 'REM';
        src: url('../fonts/rem/REM-VariableFont_wght.woff2') format('woff2');
        font-weight: 100 900;
        font-style: normal;
        font-display: swap;
    }
    
    @font-face {
        font-family: 'Nunito';
        src: url('../fonts/nunito/Nunito-VariableFont_wght.woff2') format('woff2');
        font-weight: 200 1000;
        font-style: normal;
        font-display: swap;
    }
    

    ✅ Always use font-display: swap for faster visible text.

    3. Enqueue fonts.css in functions.php

    Load your local fonts CSS using wp_enqueue_style:

    
    /**
     * Enqueue theme styles and fonts.
     */
    function mytheme_enqueue_styles() {
        wp_enqueue_style(
            'mytheme-local-fonts',
            get_template_directory_uri() . '/assets/css/fonts.css',
            array(),
            wp_get_theme()->get( 'Version' )
        );
    }
    add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_styles' );
    
    

    ✅ This makes fonts available globally on the frontend.

    4. Register Fonts in theme.json (with src!)

    This step is critical. Without a src reference inside theme.json, Gutenberg won’t know where to find your local fonts in the Block Editor.

    Here’s the correct setup:

    {
      "settings": {
        "typography": {
          "fontFamilies": [
            {
              "fontFamily": "REM, sans-serif",
              "name": "REM",
              "slug": "rem",
              "fontFace": [
                {
                  "fontFamily": "REM",
                  "fontStyle": "normal",
                  "fontWeight": "100 900",
                  "src": [
                    "file:./assets/fonts/rem/REM-VariableFont_wght.woff2"
                  ]
                }
              ]
            },
            {
              "fontFamily": "Nunito, sans-serif",
              "name": "Nunito",
              "slug": "nunito",
              "fontFace": [
                {
                  "fontFamily": "Nunito",
                  "fontStyle": "normal",
                  "fontWeight": "200 1000",
                  "src": [
                    "file:./assets/fonts/nunito/Nunito-VariableFont_wght.woff2"
                  ]
                }
              ]
            }
          ]
        }
      }
    }
    

    ✅ Notice each fontFace block includes a local src path to the .woff2.
    ✅ The Block Editor and the frontend now both load the same fonts — no mismatch warnings.

    Do You Still Need Static Fonts as Fallback?

    For 99% of projects today? No.

    All modern browsers — Chrome, Firefox, Safari, Edge — support .woff2 variable fonts. Adding static .woff2 or .ttf backups only bloats page weight.

    Only consider static fallbacks if:

    • You have strict enterprise requirements for ancient browsers.
    • Your analytics show a significant number of IE11 or Android 5 users.

    Otherwise, skip static fallbacks and stay light.

    In Conclusion

    Self-hosting fonts is a must for performance optimized WordPress web development. By converting fonts correctly and setting up theme.json the right way, you’ll get:

    • Faster loads
    • Stronger SEO
    • Better design control

    When converting .ttf to .woff2, I liked Everything Fonts — it simply worked better than the others for me.

    Learn more about the benefits of block themes and explore a recent case study, migrating a client site from a commercial builder theme framework to a custom block theme.

    Have questions or something you got stuck on? Leave a comment or feel free to contact me.

  • WordPress Block vs. Classic Themes

    WordPress Block vs. Classic Themes

    WordPress Block Themes Offer Performance and SEO Win for Small Business Owners

    If you’ve been using WordPress for a while, you’ve likely witnessed some degree of transformation to your workflow. Wordpress, originally a simple blogging platform, has grown into a robust content management system capable of powering everything from personal blogs to enterprise websites. The Gutenberg Project that began in 2018 has evolved into a rich “site editor” experience in which anyone can build beautiful websites (relatively) easily. The site editor can dramatically improve your content creation workflow and provide more “no-code” flexibility to you as a site owner or content creator.

    What Are WordPress Themes?

    Themes are the foundation of your WordPress site’s visual identity. They define essential visual elements like your color palette, typography choices, and layouts for various content types. Your theme will establish the look and feel that makes your website uniquely yours, setting the tone for your brand’s online presence.

    Classic themes: a traditional approach

    How Classic Themes Work

    For many years, WordPress themes followed a traditional development model. Before the block editor arrived on the scene, all theme templates and parts were written primarily in PHP, with supporting CSS and HTML. This technical foundation allowed developers to create dynamic, full-featured websites but came with significant limitations for non-developers.

    If you wanted to make structural changes to your site—even something as seemingly simple as updating your logo or rearranging elements in your header—you typically needed to call a developer.

    Page builder frameworks: power tools or performance pitfalls?

    In response to these limitations, builder frameworks emerged as a popular solution. These tools promised the ability to build sophisticated websites through visual interfaces, liberating non-technical users from their dependence on developers. With the ability to click and drag elements onto your pages, creating complex layouts “without writing a single line of code” became possible (to a degree).

    But, we all know that magic has a cost. Many builder frameworks:

    • Created “div sandwiches” (layers upon layers of nested divs) that resulted in messy, inefficient code. This could make your website harder to maintain and potentially slower to load – and make it harder for Google to get to your content.
    • Introduced accessibility issues by not using semantic HTML or not having testing methods in place for keyboard or voice controls. This not only affected users with disabilities but could also impact your SEO and legal compliance.
    • Added unnecessary features in an attempt to appeal to everyone, creating bloated sites with poor performance. These “kitchen sink” approaches often included dozens of features you’d never use but that still consumed resources.
    • Sat on top of core WordPress rather than integrating with it, adding extra processing layers that could slow down your site and complicate updates.

    Block themes: the modern approach

    Better No-Code Site Building

    Block themes represent a fundamental shift in how WordPress sites are built and managed. Block themes embrace a visual, component-based approach that puts a lot of creative control back in the hands of content creators.

    With WordPress block themes, you can build and customize your entire site directly in the Site Editor. The entire experience—from designing navigation menus to crafting templates for custom post types—leverages core WordPress blocks through an intuitive visual interface.

    This democratization of web design means that you can experiment, iterate, and launch new designs quickly, with much more autonomy*.

    *There are still considerations around accessibility and functionality that may require a custom block or plugin. Built-in checks in the editor are pretty good at alerting you to common issues such as poor contrast between text and background colors or skipped headings (when you view your page in outline mode). I do recommend the Accessibility Checker plugin by Equalize Digital to help you identify and fix accessibility errors. And, please – never, ever use an accessibility overlay.

    How block themes make WordPress management easier for non-technical business owners

    For small business owners, the traditional WordPress development cycle often meant expensive developer retainers or settling for a website that couldn’t evolve with your business. Block themes eliminate this frustration by putting you in control of your most important digital asset.

    Greater control, less dependance on custom code

    Using block themes enables you to incorporate sophisticated site elements that would typically require developer intervention in classic themes. Want to customize how search results appear on your site? You can do that. Need to create a more helpful and branded “404 Page Not Found” experience? That’s within your reach too. Considering a global update to your headers and footers across dozens or hundreds of pages? With block themes, these changes can be made quickly and consistently without writing or editing code.

    The modern architecture of block themes delivers tangible performance benefits through more efficient code and smarter resource management. The conditional asset loading approach means your site only loads what it needs for each page, rather than burdening visitors with unnecessary resources. This translates to faster load times and a more responsive user experience—factors that influence everything from visitor satisfaction to search engine rankings.

    Perhaps most importantly, working with a block themes represents an investment in future-proofing your digital presence. WordPress core development is clearly focused on expanding and enhancing the block architecture. By embracing this approach now, you position your website to seamlessly adopt new features and capabilities as they emerge.

    WordPress Classic Theme Limitations

    Even when using the block editor with classic themes:

    • Not all block properties will be available (unless specifically enabled)
    • There’s no front to backend visual parity: the page editor appears as a white page with black text, disconnected from your site’s design (unless you enable site editor styles and pursue a hybrid approach)

    WordPress Block Theme Advantages

    Block themes offer:

    • A seamless visual experience between editing content and the results you see on your live site
    • Enhanced design options for dynamic content (like the Query Loop block)
    • Automatic reflection of your design choices (fonts, colors, styles) in the editor and on the frontend of your website
    • More engaging, dynamic page layouts possible without developer assistance
    • Ability to load custom, branded patterns for use throughout your website for more consistent design even when you have multiple editors (to be fair, you can do this in classic themes also – block themes take it a bit further with the ability to create theme specific section styles and settings)

    By reducing dependence on developer assistance for routine website updates, block themes can significantly lower the total cost of website ownership for small businesses, allowing you to allocate resources to other critical areas of your operation.

    Performance comparison: block vs. classic

    All WordPress sites, whether using a classic theme or a block theme will benefit from recent core updates. Performance improvements are more dramatic when you use a block theme.


    Classic Themes Can Be Slow…

    • Rely heavily on PHP for rendering templates dynamically
    • Increase server-side processing time and database queries
    • Store changes via the WordPress Customizer or manual edits
    • Load large, comprehensive stylesheets and scripts regardless of what’s used on the page

    Block Themes are Super Fast!

    • Use theme.json files and block-based templates
    • Store global styles in the database via a theme.json file
    • Employ conditional loading to include only assets needed for specific blocks
    • Reduce unnecessary database queries and server-side processing

    SEO benefits of block themes

    Block themes have several SEO advantages:

    Speed and Technical SEO
    • Faster loading times positively impact search rankings
    • Cleaner code improves crawlability and indexing (this can vary depending on the theme you choose and what else you’ve got happening with plugins, etc)
    Mobile Optimization
    • Inherently responsive (intrinsic) design aligns with Google’s mobile-first indexing
    • More uniform adaptation to various screen sizes – if you can include some clamp sizing rules for layout, fonts, and spacing in your theme.json file you’ll go far with core blocks!
    Performance Enhancements
    • Reduced dependency on plugins and multiple stylesheets*
    • Style loading only when needed improves Core Web Vitals scores
    • Better user experience translates to improved search performance

    *For reference, a migration I did a few years ago cut about 3,000 lines of custom CSS from the stylesheet – and that was a hybrid theme.

    Should your small business switch to a block theme?

    Short answer: If you’ve been considering a website update or rebrand in the next 6 months – YES, ask your developer about block themes.

    Making the transition from classic to block themes is a significant decision. While both block and classic themes can perform well with proper optimization strategies like effective caching and image compression, block themes offer compelling advantages that are becoming increasingly difficult to ignore.

    The significant performance gains alone would make a compelling case, but when combined with the potential for reduced design and development time and greater flexibility for content creators and site owners, the argument for block theme development becomes even stronger.

    Block themes represent not only the future of WordPress, but its present reality. By adopting this approach now, you ensure your site can take full advantage of current capabilities while also being able to implement future improvements as they’re released.

    A teacher trains business owners to use block themes

    Block By Block: How Small Business Websites Gain a Competitive Edge with Block Themes

    Subscribe and you’ll get 1 email a week for 7 weeks that covers the competitive advantages of WordPress blocks and block themes as well as pro-tips to help you improve your current WordPress powered website.

    This field is for validation purposes and should be left unchanged.
    Name
  • “Sendig,” Designing in Public

    “Sendig,” Designing in Public

    Designing for the Site Editor

    Sendig, Screenshot of the front page of the theme.

    Flashback to September 2022. Full Site Editing (FSE), introduced in 2020, extended the visual design capabilities of the WordPress block editor allowing anyone, regardless of their coding knowledge, to build templates and template parts directly in the WordPress editor. Full Site Editing elicited many Feelings(™) from designers and developers using WordPress who had established workflows and potentially complex development needs which the site editor was still a bit clunky with. The question of “who is this for?” was (and is) an ongoing discussion. 

    A freelance, self-taught web designer, I was mainly using the blank Underscores theme as my base, and feeling like maybe I had the hang of this web design thing. Googling how to do something in PHP was/is still a major part of my development process so the idea of being able to visually design themes was quite attractive. The web, after all, is fundamentally about the democratization of publishing, so, all signs pointed to “Yay!”.

    But… the site editor (formerly known as Full Site Editing) is a completely new thing. Completely new things are hard. 

    Community and Collaboration

    When Jonathan Bossenger posted a request for a block theme design on Twitter, I volunteered. Jonathan is a Developer Educator for WordPress and I had recently begun following his training modules on Learn WordPress. Learning from a legitimate “real” developer*, as opposed to fumbling through Stack Overflow posts, promised to be much more illuminating.

    * As a web designer at the very front of the front-end, there’s a lot of things that I can understand conceptually but I just don’t have the skills to create from scratch.

    Note to Designers

    It’s especially informative for ANY designer to understand how a developer might read your designs and interpret them. If you are new-er to designing for the web, or even a seasoned pro, it’s super-beneficial to get involved in the building and thinking process rather than just delivering a design file and calling it a day. 

    Style elements for Sendig theme in a Sketch file
    Sendig theme styles outlined in the Sketch file.

    Make Web Design Fun!

    Jonathan graciously accepted my offer to design a theme for the block editor. Uh oh – now I have to design something that can withstand the critical gaze of #DesignTwitter! 

    Mostly, I wanted web design to be fun again. My approach was to do things that my standard client work would not be receptive to and have some fun with design challenges that would be more tricky for me to code.

    It starts with a name…

    I chose “Sendig” as my theme name because it sounded kind of cool and it’s also an anagram of the word “design”. 

    Boston City Hall, Boston, Massachusetts Stencil on the left plant pot: "Reaganomics is welfare for the Pentagon"
    Boston City Hall, Boston, Massachusetts. Stencil on the left plant pot: “Reaganomics is welfare for the Pentagon“

    Aesthetically, I really enjoy Brutalist architecture and design. I like showing the structure of things as well as bringing back some vintage web conventions such as a visited link color. I spent some time reviewing the structure of the Figma* file for WordPress Twenty-Twenty Three theme** and patterened my Sketch file after that.

    You can view and download the Sketch file for Sendig here: https://www.sketch.com/s/ef210a7a-a623-4353-be26-bf45d37e2d29

    Figma File: https://www.figma.com/file/HCajUTUN2NVNfYA4FKTQN0/SENDIG—FSE-Theme-(WIP)?type=design&node-id=0%3A369&t=94yVg0XwavbR8ark-1

    * Maybe I’ll learn Figma someday. For now, Sketch or Balsamiq are easier for me.

    ** WordPress has a Figma design library and many other resources through Make WordPress Design.

    Can a free theme also be a teaching opportunity?

    I was thinking, instead of Lorem Ipsum text, what if we included some hints about accessible design considerations within the text of the theme? Maybe a little learning mixed into the theme could help to keep accessibility in mind when creating a new website?

    So, I probably have to change this to something from Web AIM or a more general source, but I chose to use some quotes from Steve Krug, author of the classic text “Don’t Make Me Think,” and a quote from Marcy Sutton’s recent accessibility training course, Testing Accessibility.

    Headings in the design also describe their purpose; introducing a new section or topic and helping to create good page structure.

    Design is Problem Solving

    I wanted to do some design-y things that tend to be less applicable to my commercial work – such as aligning main content to the left rather than centering it by default or using “not typically considered beautiful” colors like mustard yellow (aka. Yellow Ochre for the painters). And, I wanted to do some fun CSS things like shapes, overlay/opacity, transform, and layering of elements in space.

    A sample pattern shows a "scatter" design with images around a block of text.
    The scatter image pattern in color.

    I’ve created a few patterns that reference “classic” graphic design motifs like scattered images around a block of text. These patterns would be hard for me to create in the WordPress site editor (without relying on custom CSS and code) so I’m keen to see how they develop through this process.

    Developing the Sendig Theme in Public: The First Twitch Session

    After several months, the first Twitch development session took place on this auspicious day, May 9, 2023. Today was mostly set up and although Jonathan called it the “boring” part, it’s always informative to me to learn how other developers structure their process, what tools they use, and how they approach a project.

    In that sense, I find developing to be closely related to painting. In practice, all painting is essentially abstract. When observing a structure or a landscape, what we see is broken down into colors, shapes, and light (or, components) as we understand how all the parts can fit together to compose a whole. In painting, an expression of feeling supersedes exactitude. Which, for better or worse, also tends to be my design approach (apologies in advance).

    Live streaming this process highlights the thinking that underpins any project. There is no such thing as a perfect design to dev handoff (at least, not in my experience). Communication, collaboration, and ongoing inquiry are key. And, love it or hate it, we are all learning this new thing together, which is pretty cool!

    I’m looking forward to continuing to follow this project on Twitch on Tuesdays and I hope you will to. 


    Project Links:

    A few resources to learn about block themes:

    • I recommend Daisy Olsen’s Twitch stream which you can see archived on YouTube. Her block theme experiments are a great learning experience.
    • Full Site Editing training site by Carolina Nymark, https://fullsiteediting.com/
    • Bill Erickson shares a lot of useful info, snippets, and resources.
    • Just launched by Aurooba Ahmed, Thoughtful Block UI. The podcast, viewSource, with Aurooba Ahmed and Brian Coords is more advanced development and also highly recommended (most of it is beyond me but I still learn a thing or two).
    • Build Mode Live, an ongoing and open Zoom conversation each Friday morning (10am CST) hosted by Sam Munoz and Brian Gardner from WPEngine about the future of WordPress and the site editor.
    • Gutenberg Times, “All things WordPress Block Editor and Gutenberg Plugin”!
    • WP Café is a podcast that’s a bit more about the business aspects around theme development but also documents their transition into learning and using the block editor for client work.
    • MasterWP, not specific to block theming but a great learning resource: https://masterwp.com/
  • From Builder to Blocks: A Rebuild Experiment

    From Builder to Blocks: A Rebuild Experiment
    DSGChicago.com home page

    The good thing about looking back at early work, is seeing how much you’ve learned.

    I built the first website for the law firm of Despres, Schwartz, and Geoghegan, Ltd. around 2015. They needed a responsive website (migrating from a classic table layout) and WordPress seemed the right solution. I used my premium theme builder and created a simple website with a few pages and a blog. 

    After nearly ten years, the site desperately needed a rethink. Rebuilding in the site editor this year was an opportunity for me to explore (and learn) what might be possible in a block theme on a “real”1 website. 

    1 Some anti- block-theme sentiment spirals around block themes being fine for displaying simple content but not functional for the complexities of an actual website.

    Create Block Theme Plugin

    The Create Block Theme plugin is not required but it sure does make things easier. For example, creating a child theme (unclear if this is still as essential with block themes as with classic themes), including fonts in theme.json, or even just setting up a new “empty” theme with the basic structure and files you need to get started. When you generate your theme, it will create the theme folder in the site’s theme directory. You can also choose to export your theme.

    Using this plugin I first created a child of the theme Beaumont by Anders Norén (because his designs are so great). At some point, I decided it wasn’t quite right – I didn’t really want any styling to exist, just the basic structure. I opted for something more stripped down, Blockbase. In this attempt, I didn’t create a child at first. I chose to create a style variation for the current theme thinking, “Let’s keep this simple – I’m just customizing styles and blocks, right?” 

    As many of us know, simple soon becomes complex. I experimented in changing my selected style variation to see what would happen if an editor did that. All of my customizations were lost, probably due to me not saving my changes.

    Lesson #1:
    Always save your work

    Save changes as you go!

    We can make a whole lot of changes in the site editor very quickly and saving changes isn’t an obvious part of the flow (as it is when you are working directly in a file editor). A nice feature in Create Block Theme, which I discovered through doing things wrong, is that in addition to saving your theme at any point through the Create Block Theme dash, you can also write your user changes (to styles and templates) to the database while working in the site editor. The wrench icon opens to display your save options: 

    • Save Changes saves everything to the theme. 
    • Export zip exports your theme but you also want to be sure to “save changes” to your theme first or they won’t be included (learned this the hard way!)

    Notifications are a little too discreet here. I’d like to see an alert or something that repeats the description of what to expect, like: “You may want to save your user changes to the theme first or they won’t be included in your exported theme.” A message when you change your variation would be nice too. If the site editor can note that changes have been made, but not saved, remind me. Especially for a new user or non-developer, contextual messaging about what happens next could help them from feeling frustrated that things appear broken “for no reason”.

    Revision history in the site editor

    We can view a list of changes and revert to a previous version using the revision history panel in Styles.

    3rd (or 4th) time, the charm

    I began again with a copy of Blockbase and got pretty far with my new theme until I read somewhere that it should be a child. Or, maybe I began second-guessing myself and thinking, “this should be a child,” in case the parent theme is updated. Once more, I returned to the beginning and created a child of Blockbase.

    Some minor issues that happened at various points in development: 

    • At one point, the social links block was missing the setting to change the link color on icons. I could change the block background and text color but not individual link icons.
    • The height unit for spacers stopped working. The values are displayed in the spacer block settings (em, rem, px, vh) but only the pixel value would change the height. 

    I’m not sure if those bugs are related to some glitch that may have happened during a save/write to theme files.

    Major Mental Model Shift

    The most challenging aspect of working to create a block theme, for me, was not relying on editing files directly. It felt a bit like I was working with blinders on, unable to see the actual code. I could work on theme.json initially in my code editor but after a certain point what happens in the code editor and what happens in the site editor starts to break down (as one might expect in a mirror universe). This is because what’s happening in the site editor is being written to the database, which is not the case when editing files outside of WordPress (I think).

    Why can’t I just write CSS?

    Add CSS – if you dare!

    I don’t like the tiny little panel we get for custom CSS stuff. “Additional CSS” isn’t even exposed by default. It’s like, don’t you want me to write CSS anymore, WordPress? Where block themes are currently, and what theme.json can control, is pretty awesome. But, there ends up being a fair amount of CSS we designers and developers will want/need to add in a custom theme. Even a block theme. The few examples that occurred in this very basic site involved:

    • Custom bullet styles for unordered lists
    • Overwriting a form plugin gap and required field color in order to meet color contrast requirements
    • Creating a negative margin style so that an image could “overlap” a section
    • Adding a transition to buttons to ease the background color shift
    • Many styles to adjust the navigation block

    Which brings me to the navigation block.

    Navigation Block: Bane or Boon?

    The great thing about the navigation block is that it has accessibility baked in. A parent item with children is a button element. Keyboard interaction is as expected. Yay! But … there’s a few things that are hard here:

    • I want the .current-menu-item li to have some style that shows what is current and active in the menu, like a bottom border.
    • If a page is a pseudo parent, for example, a static team page contains the custom post type team, I still want to highlight the parent page when viewing a single team member (post).
    • I also had this issue with the /blog/ page menu item when a single post was viewed. Even with a .current-menu-item style, I had to add another custom style for this to work on the archive view.
    • The mobile menu: there’s minimal and then there’s, um, the mobile menu for the navigation block. Compared to what we are used to, it’s too limited. I want to be able to show the word “Menu” and “Close” as well as the icons. I also want to be able to change alignment and styles here.

    Your selected, primary navigation menu is synced: a good default but not obvious.

    When adding the navigation block to the footer template part, I customized it not realizing that the navigation block was by default my “primary” navigation and synced with the header navigation. 

    Under the navigation settings, the title is simply “menu” and then menu items are listed. It wasn’t obvious that this is a specific default menu that would also be synced. If I click on the options menu, I can see that I am able to import classic menus or create new menus. If the selected menu name was also shown in the settings panel, not just the “Menu” label, we might infer multiple menus could be created and managed and that changes to a current menu would affect all instances of that menu.

    Search Icon, wherefore art thou?

    A search icon that opens up a search panel is ubiquitous in website designs. The search field is probably better UX but it’s not always going to work in those minimal header designs with a logo to the left and navigation to the right. My work around on this website was to use a modal block and, basically, fake it.

    Working with Page Templates

    As I neared the end of the rebuild I started to use Polypane for a look at responsive and accessibility issues. One thing immediately noted was that the Page Title was not in a landmark. That’s not good! I checked my page template and realized that the Page Title, which has a full-width cover image background, was indeed outside of the <main> content group. 

    The main group has a margin that doesn’t allow for full-width inside the template. On a page, you can include full-width blocks but not inside the template (I’m not sure why, to be honest). I referred to my usual _S (Underscores) theme structure within the body:

    <header>
    <nav></nav>
    </header>
    <main>
    <article>
    <header class=”entry-header”>Page Title</header>
    <div> The Content </div>
    </article>

    </main>
    <footer></footer>

    Since we can define the HTML element under the “advanced” settings of the group block, I added two more container groups to create the missing article and article header sections and grouped everything in a new <main> section. I then demoted the <main> content group to a general purpose div.

    This is something that will vary by theme since the theme author decides the structure when they build their templates. It’s not something everyone would investigate. More explicit instructions could be useful, for both DIY folks and developers. Landmarks may not be top of mind for everyone when building out a template and even developers aren’t always aware of their importance to accessibility. 

    • This setting is hidden under an advanced label. The name “advanced” would probably deter many content creators from even looking here.
    • Could there be a warning / “are you sure” message if a landmark is missing from a template?
    • The descriptions are a little vague, for example: “The <section> element should represent a standalone portion of the document that can’t be better represented by another element.” 
    • Some examples or a link to learn more about each type of element could be useful, as we have for the HTML anchor option.

    File under “Miscellaneous”

    One thing that is necessary for larger sites is handling custom field data. I use Advanced Custom Fields (ACF) on many of my sites. I likely want my custom field content to appear dynamically in certain places and not just the page or post it is created on. Here’s where I start to encounter a knowledge chasm going from classic theme to block theme developer. 

    I am not a person who will be able to “learn JavaScript, deeply”. Learning new things is hard, which doesn’t mean I won’t try, but it’s really hard not possible to keep up on everything and do it well. I am excited about the potential of the site editor and block themes. I’m a little sad to lose the control and autonomy I had with my _S based theme process. 

    There is a middle path (for now)

    Hybrid themes afford someone like me a viable option for sites of any complexity. I kind of understand PHP now and I am able to manipulate it. With the inclusion of theme.json, some editor styles, and custom blocks I can leverage the more modern aspects of WordPress core. But, if I see an opportunity to go full-on block theme I definitely will.

    Re: Block theme and site editor resistance

    When I was first introduced to WordPress, I had been building websites using BBedit and Dreamweaver. I started by creating child themes but, not knowing any PHP, there were many things that I couldn’t do. Using a builder framework offered me much more design control and a speedier process (in theory). Gradually, I tried to improve my processes to follow what I considered to be “best practices” – relying on defaults, using semantic HTML, prioritizing accessibility in design. Using a builder began to feel confining because I didn’t want to just do it faster and increase my volume to make more “web product”. I wanted to craft the web experience more holistically and have a meaningful personal and professional investment in my work. Or, maybe I just like doing things the hard way.

    Despite the recent advances of the site editor, builder frameworks are still a prevalent solution and the default editing capabilities of WordPress are often compared negatively. Most commonly, the developer complaint is that the block editor is great in theory but it’s still too new and not capable of the robust solutions (ie. control) we developers have in our established themes and plugins of choice. That always makes me think of the agency job I had 5 or 6 years ago where my manager vetoed the use of CSS Grid for the same reason. It’s been almost seven years, that’s super old in internet years? But, okay, I get it.

    “Mostly in” on Block Theme Development

    When web creators push back and say something is too new to use, often that means, “I’m not comfortable with this change and I’m worried about all the additional labor needed to understand this.” Once that knee-jerk “no” is out of our system, I think we can acknowledge that adapting to change is one of the strengths inherent in our practice. And, if that doesn’t inspire you, the block editor is here to stay. It’s on us to learn and understand more fully what is possible – and to work together to make it better.


    View the new site at DSGChicago.com.

  • The Panama Papers & WordPress Plugin Security

    The Panama Papers & WordPress Plugin Security

    Well, I’ll just leave my keys in the car door tonight. They’re so heavy and jangly. Carrying things is hard.

    Someone

    It’s a Big, Bad, World Wide Web. Is Your Website Secure?

    The absurdity of the above example is not that different from complaining that your password is too hard to remember or hosting a bunch of inactive, outdated plugins on your WordPress site. When it comes to the security of your website, it’s definitely worth the time spent to fortify its defenses.

    And, hey, guess what? Trying to remember all of your unique, strong passwords is impossible! Scrap that password spreadsheet you keep on your computer (which, if hacked, becomes a liability) and use a password manager to safely generate, store, and share strong passwords.

    How The Panama Papers Leak Affects You

    Some list confirming that a bunch of world leaders and celebrities have secret stashes of untaxed money shouldn’t exactly concern you on a personal level, right?

    Well…

    The vulnerability that led to the largest data leak of all time actually stems from something we all use regularly, whether you’re a business owner, developer, or a consumer — Wordpress. It’s almost difficult to believe, but a widely-used plugin just so happened to spark the collapse of …well, the entire world. (Or, at least, it has definitely changed how the global public handles its leaders and the rest of the 1%.)

    Let’s review how a failure to update a WordPress plugin very quickly turned into a worst-case scenario and PR nightmare for Mossack Fonseca, a Panamanian law firm that is known to be, wait for it… a “leading global provider for legal and trust services.”

    Last week, WordFence, a software engineering team and makers of the Wordfence WordPress Security plugin, broke the story of a massive Mossack Fonseca breach, citing a vulnerability in the firm’s version of the Revolution Slider plugin.

    That particular vulnerability was actually old news; the exploit was published in September of 2014 and the Revolution Slider plugin had since been patched and updated multiple times.

    Many commercial WordPress themes come bundled with Revolution Slider and other cool plugins. These themes generally require a renewal payment every 6-to-12 months to maintain access to updates and support. But, if your web developer doesn’t hang around to keep your site updated, or worse, installs a theme that THEY purchased and own the license to, you could have a problem down the road.

    Top 5 Reasons Web Sites Get Hacked

    Many website owners may not even be aware that they are hosting similar vulnerabilities simply by not maintaining their website frameworks, plugins, themes, browsers, and operating systems. Yes, that’s right — even browsers and operating systems.

    #1) Failure to Update

    WordPress.org and its community of developers all agree that failure to update is the leading cause of hacked sites.

    In a quick follow-up article to the Mossack Fonseca breach, WordFence described how the Panama Papers debacle was likely a lateral move for the hackers, explaining: “Once you gain access to a WordPress website, you can view the contents of wp-config.php which stores the WordPress database credentials in clear text. The attacker would have used this to access the database.”

    By hosting known vulnerabilities you’ve essentially given away the keys to your car, left your address on the dash, your apartment door wide open, and your bank card and pin number under a plate of cookies in the kitchen. Thanks!

    Hackers aren’t sitting around trying to guess YOUR password as Matrix code cascades across several monitors. The majority of attacks are automated and impersonal. Their aim is to identify easy access points (known vulnerabilities) that offer the greatest ROI.

    Secure your site to protect not only your information, but that of your customers and business partners, too.

    If you site is compromised, other plugins that you might be using, like the popular WP SMTP Mail (which gives you the ability to send mail from your website via a mail server), can now also be accessed and reveal not only your email and password but also provide hackers access to everyone in your address book.

    To see just how prevalent this is, you can view a cool animation of real-time attacks on the WordFence website, which shows a mere 4% of the 10,963 attacks happening per minute.

    #2) Cheap, Insecure Web Hosting

    If you are in business, invest in your infrastructure. You can pay $25/month for WordPress managed hosting.

    This is not just about your data, it is also about your clients’ and customers’ information. If you are building a site with WordPress, look for managed WordPress hosting like WPengine or SiteGround. Read this article by Joost DeValk about recommended web hosts for WordPress websites.

    While you are at it, secure your site with HTTPS://. Most web hosting companies provide free auto-ssl certificates these days. Google prefers it and it is part of a larger HTTPS Everywhere movement to make the web more secure.

    #3) Your .htaccess Permissions Are Set to Read/Write All

    Lock down your file permissions. Folders like /wp-admin and /wp-includes should not be writable by anyone but you. You can do this in your .htaccess file and there are also some good WordPress plugin solutions that can also do the job.

    More information about hardening WordPress can be found in the WordPress codex.

    If you wouldn’t make copies of your house keys for everyone on your block, why would you want to give everyone who uses your website Administrator level access?

    Hacking is most often an exploit of ease and opportunity. The more Administrators you have, the more possible points of access to your website or other accounts.

    Understand who needs what privilege when it comes to doling out the editing and content creation roles. And, please don’t email your login information. Email is not secure. Try sharing access with a tool like LastPass.

    Have an internet safety process in place. Make sure that people with access to sensitive accounts aren’t using free WIFI connections or sharing their unique logins with others. Use a secure, modern browser (like Chrome, Firefox, or Safari) and make sure that you have some type of anti-virus protection installed on your computer as well as a separate backup method. Don’t rely on time machine alone.

    #5) Using Default Usernames and/or Weak or Duplicate Passwords

    Everyone knows this now, right? The default username in WordPress is “admin”. Don’t use the default username on your WordPress site.

    • An 8-character password can be cracked in less than an hour.
    • Use a passphrase instead of a password.
    • Use a password manager and make sure you have unique passwords for your online accounts.

    WordPress does use strong passwords by default, but people still like to simplify their lives and create passwords that are easy to remember. 2-factor authentication is recommended if you can get people to activate it.

    Do’s and Don’ts

    • Do not store passwords in your BROWSER. If you lose your computer, you also lose your passwords. If your computer gets hacked, your Keychain Access is EVERYONE’S Keychain Access.
    • Email is not secure. Do not share logins or other sensitive data via email. If you sign up for LastPass (it’s free by the way) you can share passwords with other LastPass users without revealing your login. Then, remove access when your collaboration is over.
    • Use unique, randomized passwords. Always.

    Ignorance may be bliss but it’s not a website maintenance plan

    If you are part of a large organization, maybe you inherited a system that has seen many makers and is now too convoluted to update without breaking needed functionality. Or, you are a lone business person just trying to find time to add a new blog post and are waiting until you can afford a site redesign to make updates.

    Unfortunately, “not knowing” is not a defense against malicious attacks or exploits. Just like owning a car, we may not understand exactly how everything works, but we do accept a basic awareness and responsibility for its use and maintenance. As website owners, and daily users of technology, we would be wise to note that the probability of attacks increase in direct proportion to the popularity and market share of the given product.

    WordPress and your “virus-proof (not!)” Mac are glowing red targets because of their ease of use and popularity with consumers. That doesn’t make them bad technology solutions. In fact, open source applications like WordPress benefit from having an active community of dedicated programmers constantly finding bugs and patching them. It just means you have to be proactive.

    Although exploits in the wild WWW will always exist, the best practices outlined above are mostly common-sense and really don’t change at all when it comes to securing your website and online accounts. This doesn’t mean that you will never suffer a hack or data-loss, but awareness and good online habits in the areas that you do have control over will make you a less-likely target.

    Don’t assume that your web developer (or your best buddy who’s building your website for free) is taking care of the site’s maintenance and security. Take ownership of your technology. Ask your developer, “Will you maintain my website security once my site is launched and what best practices have you put in place?”

    Further reading

    The following links can help you learn about site security and take action to strengthen your site’s defenses: