Normal view

There are new articles available, click to refresh the page.
Before yesterdayDelicious Brains

WP Offload Media 3.4 Released: WordPress 7.1 Compatible, Preparing For Future Features & Performance Improvements

By: Ian
3 September 2026 at 09:00

We’re super excited to bring you a new release of WP Offload Media.

Version 3.4.0 delivers full support for WordPress 7.1, performance improvements and bug fixes, along with foundational changes that unlock future features and further performance improvements.

WordPress 7.1 Compatible

WordPress 7.1’s client side media handling brings along three new fields to the _wp_attachment_metadata records in the postmeta table related to Media Library items.

Namely:

  • source_image: The uploaded image file that needed to be converted to another format, e.g. an HEIC file.
  • animated_video: The MP4 file created from an uploaded animated GIF.
  • animated_video_poster: A JPG extracted from an uploaded animated GIF to act as a placeholder for the MP4 version.

WP Offload Media now knows about these extra files, and will offload and remove them from the server as appropriate.

To accomplish this, we had to tap in to some in-progress changes to the plugin.

Preparing for the Future

We’ve been working on some changes to the internals of WP Offload Media to prepare for some features our customers have been asking for, while also improving performance, especially for sites with very large Media Libraries.

Custom Table Changes

When you upgrade to WP Offload Media 3.4.0, depending on how many offloaded items you have, you may see an upgrade notice in the settings page.

This upgrade routine will quietly background upgrade WP Offload Media’s metadata related to offloaded items to create a new as3cf_files table that lives alongside the existing as3cf_items table.

Although you won’t be able to make any changes to WP Offload Media’s settings or run any of its bulk management tools while this upgrade is in progress, all existing and new offloads will continue to work as usual.

This new as3cf_files table holds a wealth of information:

  • 1-to-1 mappings of local media files to their path in the cloud storage bucket.
  • Information related to whether the files are private in the bucket or not.
  • A reference to the as3cf_items record which ties multiple files to a Media Library item or BuddyBoss avatar or cover item.

Performance Improvements

The as3cf_files table gives WP Offload Media much improved flexibility in how it keeps track of offloaded media, crucial for supporting the new Media Library metadata fields mentioned above.

However, the new table’s data structure also makes it far simpler and therefore faster for finding matching records when performing unique name checks, or rewriting URLs between their local and remote versions.

WP Offload Media no longer needs to reduce file names down to their base non-sized suffixed name and do potentially expensive LIKE table scans, it can do much simpler equality checks that use indexes for speed.

Because of these changes, it has been possible for us to reduce the processing required when doing URL rewrites. We’ve removed a whole pass through post content and its associated processing, and removed other loops that are no longer required.

We’ve also been able to vastly improve the way we cache the relationship between the URLs in a post’s content with their associated Media Library items. As such, you may see a second upgrade routine notice related to the removal of ye olde amazonS3_cache records from the postmeta table, which will be replaced by much better behaved as3cf_url_cache_local and as3cf_url_cache_remote records.

And for our most advanced customers that have their whole site behind a CDN such as CloudFront, and only use WP Offload Media to manage media in the bucket, we have a big performance boost for you. WP Offload Media no longer implements many of the usual frontend content filters if “Deliver Offloaded Media” is turned off, cutting out a lot of unnecessary checks and processing.

Small Steps

Along with the custom table changes that unlock future features and performance improvements, WP Offload Media will need to change how some of its internal code is organized.

We’re very lucky to have a number of plugins that integrate with WP Offload Media, and are aware of many customers that have custom code that relies on the existing internal API.

As such, we’ve been very careful to make these changes in a backwards compatible way, keeping the existing as3cf_items table data in sync with the data managed in the new as3cf_files table, and ensuring the classes and methods that work with the old data still work.

However, we have marked some functions as deprecated, and do intend to eventually remove them.

Our work in this area is not complete. WP Offload Media still uses some of the deprecated methods itself, and we have plans for further improvements to the data handling that unlock some exciting features, and continue to improve performance.

And More

As always, there’s a number of other bug fixes and improvements in this release.

For a full list of new features, improvements, and bug fixes, see the 3.4 Changelog.

Next Up

We hope you enjoy this foundational release of WP Offload Media.

We’re already working hard on the next release, and are excited to bring you the features and improvements you’ve been asking for.

The post WP Offload Media 3.4 Released: WordPress 7.1 Compatible, Preparing For Future Features & Performance Improvements appeared first on Delicious Brains.

Delicious Brain Bytes: WordPress Market Share Declines, State of the Community Survey, and Building an Admin Copilot

8 June 2026 at 20:22

In this issue of Delicious Brain Bytes, we look at the recent WordPress® market share decline, dive into Brian Gardner’s perspective on WordPress 7.0 as a design-focused operating system for the intelligent web, check the pulse of the ecosystem with the WP Community Collective’s State of the Community survey, and much more!

Unpacking the WordPress Market Share Decline

The WordPress community has been abuzz with recent data showing a contraction in its once-untouchable market dominance. According to the latest data from W3Techs, WordPress currently powers 59.4% of all websites with a known content management system, which translates to roughly 41.9% of all websites on the internet. While those numbers still represent a massive amount of sites, the trajectory has raised eyebrows across the industry.

As reported in a detailed analysis by Search Engine Journal, WordPress is facing its first sustained, multi-quarter decline in recent history. While a minor drop in 2025 was easily dismissed, the pace of the decline seems to have picked up.

“WordPress market share stood at 43.20% in December 2025 and declined to 41.90% by May 27, 2026. That’s a drop of 1.3 percentage points in six months, double what it was for the entire year of 2025,” writes Roger Monti on Search Engine Journal. “That’s a drop of 1.3 percentage points in six months, double what it was for the entire year of 2025.”

Where are these users going? While WordPress has dipped, closed-ecosystem competitors and modern developer frameworks are steadily scooping up the crumbs. Over the same timeline, platforms like Wix (+0.6), Shopify (+0.4), and Squarespace (+0.2) have seen modest gains.

WordPress Core Calls: Test Client-Side Media and Join the 7.0.x Release Squad

The WordPress core team has issued a call for testing client-side media processing, a progressive enhancement targeting WordPress 7.1 as a core capability. Rather than depending solely on server-side image processing pipelines, this feature offloads the decoding, resizing, and encoding of images directly to the user’s browser using WebAssembly. It provides a uniform, high-quality experience across different hosting environments while supporting advanced formats like AVIF, WebP, HEIC, UltraHDR, and JPEG XL without bloating initial bundle sizes. Testing across diverse devices is highly encouraged to smoke out bugs and stress-test upload resilience paths before the 7.1 cycle accelerates.

There’s also an open call for WordPress 7.0.x release managers to steer minor maintenance versions. This lean squad will be responsible for triaging bugs, drafting announcements, and running release operations, beginning with the tentative rollout of WordPress 7.0.1 later in June.

State of the Community Survey Now Open

The WP Community Collective has launched its State of the Community survey, an anonymous initiative inviting anyone who works with, contributes to, or cares about the WordPress open source project to share their perspectives.

Open from May 27 through June 28, 2026, the survey takes 10 to 20 minutes to complete and aims to capture a comprehensive snapshot of ecosystem health and participant trajectories.

Rather than just collecting basic demographics and professional background, the 10-to-20 minute questionnaire gathers broad feedback on project sentiment, community and event participation, core open-source values, and the shifting impacts of artificial intelligence.

All responses are completely anonymous and will be used to better understand the collective state of the project. To make your voice heard, head over to the WPCC and share your feedback before the June 28 deadline.

WordPress 7.0: A Design-Focused Operating System for the Intelligent Web

Brian Gardner of WP Engine recently shared a deep-dive perspective on the release of WordPress 7.0. Gardner notes that for twenty years, building great digital experiences often felt like a series of compromises between creative vision and software limitations. With the arrival of version 7.0, however, he believes the core software has officially matured into a sophisticated, future-ready operating system.

In the article, he explores in depth how the release transitions the CMS into an AI-ready, design-focused operating system by introducing a native AI framework, utilizing the Connectors API and WP AI Client SDK, alongside core enhancements like customizable navigation overlays, “content-only” pattern editing, and responsive block visibility.

Read the [full breakdown] (https://wpengine.com/blog/wordpress-7-0-release/) and see how these guardrails, performance updates, and media optimizations are helping to prepare your sites for the next era of web development.

Build a WordPress Admin Copilot with OpenAI and Smart Search AI MCP

“Find the right post quickly” sounds simple, but becomes more challenging as your content library grows. In an ideal world, you’d be able to search your indexed content with natural language, return results in real time, and handle follow-up requests like “show more” and “summarize the first result.”

In this tutorial, Fran Agulto shows us how to build a WordPress admin copilot that does just that, using a Next.js API backend as the coordinator, OpenAI for reasoning and tool orchestration, and WP Engine Smart Search AI MCP for deterministic search and retrieval.

YouTube cover image

Managing Third-Party API Bottlenecks in WordPress

No WordPress site is an island. Sites routinely integrate with external CRMs, enterprise ERP systems, inventory managers, payment gateways, and fulfillment APIs. These integrations add value, but they also introduce architectural vulnerability.

Any given third-party service might go down and cause a specific feature to stop working, but the bigger risk is a cascade failure. If an external API experiences latency or drops offline entirely, a poorly isolated WordPress site will go down with it.

Your server won’t crash because your database failed or because you ran out of memory. It will crash because your server’s PHP-FPM workers are stuck waiting in a synchronous queue for a response that isn’t coming.

In this article, we discuss defensive code isolation, and how to decouple your site’s frontend uptime from the reliability of your third-party dependencies.

What’s the most interesting news you’ve come across recently? Pop by the site formerly known as Twitter and let us know.

The post Delicious Brain Bytes: WordPress Market Share Declines, State of the Community Survey, and Building an Admin Copilot appeared first on Delicious Brains.

Environment Variables vs. Database: Securing the Connectors API

1 June 2026 at 16:22

With the launch of WordPress 7.0, the platform has undergone one of its most significant architectural evolutions in years. Instead of treating artificial intelligence as a collection of disjointed features to bolt on, Core now includes a standardized, native infrastructure layer.

At the center of this is the Connectors API, a centralized, native registry in WordPress 7.0 that allows you to manage your external service credentials in one place instead of forcing you to configure them across multiple separate plugins. As Greg Ziółkowski writes in the Make WordPress post linked above, “The initial focus is on AI providers, giving WordPress a standardized way to handle API key management, provider discovery, and admin UI for configuring AI services.”

While this solves a massive headache, it also introduces new questions about where and how you should stash your secrets.

Saving your keys via the dashboard is convenient, but storing scalable, high-cost AI credentials as plain text in a centralized database table has its downsides. An AI API key can essentially serve as a blank check tied to an open-ended billing account. If an attacker extracts it via the database, the financial liability could be massive. In this article, we explore why shifting your credentials to environment variables is a more secure choice.

Centralized Secrets

Before WordPress 7.0, a site using three different AI-powered plugins required pasting API keys into three entirely different settings screens. This method resulted in fragmented credential storage, messy rate-limiting, and unpredictable security risks.

WordPress 7.0 fixes this by decoupling the core infrastructure from the specific service providers.

  • Core Infrastructure: WordPress Core now provides the unified registry layer and the native API endpoints.
  • Companion Plugins: Individual service connections (like OpenAI, Anthropic, or Google) are managed by official companion plugins that register in the Core ecosystem.

The result is a centralized hub located at Settings → Connectors. While this unification provides seamless configuration, it means that a single point of entry now holds the keys to your entire external application ecosystem.

A screenshot of the "Connectors" screen in WordPress 7.0.

Understanding the Authentication Hierarchy

Securing this architecture requires looking at how WordPress evaluates credentials. The Connectors API uses a strict, three-step waterfall logic to check for API keys:

  1. Environment Variables (Highest priority)
  2. PHP Constants (e.g., define( 'OPENAI_API_KEY', 'sk-...' ); inside wp-config.php)
  3. Database Options (Values submitted through the Settings → Connectors UI)
[System Request] 
       │
       ▼
 1. Environment Variables ───► Key Found? ───► [Authenticate]
       │ (Bypasses DB)
       ▼ Key Empty
 2. PHP Constants         ───► Key Found? ───► [Authenticate]
       │
       ▼ Key Empty
 3. Database Storage      ───► Pulls Plain Text from wp_options

Defining your secrets at the server level with environment variables automatically short-circuit this evaluation chain. WordPress never triggers the database lookup for the key, reducing query load and keeping your raw credentials completely decoupled from the database layer.

“Masked” Does Not Mean “Secure”

If you input an API key into the WordPress admin interface, the screen will gracefully mask the characters with bullet points or asterisks. However, masked does not mean encrypted.

Under the hood, WordPress stores these credentials as raw, plain-text strings inside the wp_options table. Because of this storage model, your site’s external accounts are exposed to several common vectors:

  • SQL Injection (SQLi): If an unpatched plugin introduces an SQLi flaw anywhere on your site, an attacker can read the raw contents of the wp_options table and extract your production API keys.
  • Database Export Exposure: Unauthorized database dumps, poorly secured staging environments, or unencrypted backups left in public directories immediately compromise your external billing accounts.
NOTE: The WordPress community recognizes this plain-text limitation. Core ticket #64789 is actively tracking proposals to introduce native database encryption for sensitive stored options in future releases.

Database Cleansing and Syncing with WP Migrate

When transitioning from database storage to server-level environment variables, you must ensure that your deployment tools don’t accidentally leak production keys downward to local environments.

The Connectors API uses a standardized naming schema for options stored in the database:

connectors_{$provider_type}_{$provider_id}_api_key

Because these options use a predictable prefix, configuring your synchronization tools is straightforward.

Preserving Environment Boundaries

When pushing or pulling databases with WP Migrate, you must prevent sensitive credentials from migrating between environments. Use the wpmdb_preserved_options filter to ensure that local or staging variables are never overwritten by a production database pull:

add_filter( 'wpmdb_preserved_options', function( $options ) {
    // The provider type group in WP 7.0 is 'ai'
    $options[] = 'connectors_ai_openai_api_key';
    $options[] = 'connectors_ai_anthropic_api_key';
    return $options;
});

Database Sanitization

Once you have successfully declared your keys as environment variables at the system level, your site immediately switches to them, rendering the database values obsolete. At this point, you can use WP Migrate’s find-and-replace feature to search your wp_options table for the connectors_ string prefix and safely delete those obsolete records.

Wrapping Up

The Connectors API in WordPress 7.0 is a phenomenal structural step forward for the ecosystem, turning the CMS into a highly capable platform for integrated AI capabilities. However, a framework is only as secure as its implementation.

Relying on default database storage exposes your critical external integration credentials to unnecessary vulnerabilities. By embracing the authentication hierarchy and prioritizing server-level environment variables, you harden your infrastructure and protect your operational budgets.

The post Environment Variables vs. Database: Securing the Connectors API appeared first on Delicious Brains.

Managing Third-Party API Bottlenecks in WordPress

18 May 2026 at 16:52

No WordPress® site is an island. Sites routinely integrate with external CRMs, enterprise ERP systems, inventory managers, payment gateways, and fulfillment APIs. These integrations add value, but they also introduce architectural vulnerability.

The danger isn’t just that a third-party service might go down and cause a specific feature to stop working. The real risk is a cascade failure. If an external API experiences latency or drops offline entirely, a poorly isolated WordPress site will go down with it.

Your server won’t crash because your database failed or because you ran out of memory. It will crash because your server’s PHP-FPM workers are stuck waiting in a synchronous queue for a response that isn’t coming.

A truly resilient site uses defensive code isolation. Here is how to decouple your site’s frontend uptime from the reliability of your third-party dependencies.

The Anatomy of a PHP Worker Hang

When an external service drops or slows down to a crawl under heavy load, many developers assume the impact is isolated to that specific function. They believe that if the shipping calculator API is slow, only the checkout page will lag.

To understand why this is a dangerous misconception, we have to look under the hood at how PHP and your server handle incoming traffic.

By default, HTTP requests executed via WordPress core functions like wp_remote_get() or wp_remote_request() are synchronous and blocking. PHP is inherently single-threaded. When a worker process executes a blocking HTTP request, it halts execution entirely and sits idle, waiting for the external server to reply.

[Incoming Request] ➔ [PHP-FPM Worker Assigned] ➔ [Executes wp_remote_get()] ➔ [Worker Halted / Waiting for API]

Most production servers run a process manager like PHP-FPM with a finite pool of workers (for example, 20 to 50 concurrent workers depending on your server configuration). If your site experiences a sudden surge in traffic and 20 concurrent users hit a page that triggers a slow third-party API call, your entire worker pool can be exhausted instantly.

At this point, your server is maxed out. The 21st visitor will be placed in a queue, even if they are just trying to load a completely static, text-only homepage that doesn’t use the API. When the queue fills up, Nginx or Apache will throw a 502 Bad Gateway or 504 Gateway Timeout error. A slow API endpoint on a single deep page has successfully brought down your entire network.

The Transient Trap and Cache Stampedes

A common first-line defense against API bottlenecks is caching the external response using the WordPress Transients API. By wrapping your request in get_transient() and set_transient(), you ensure your server only hits the external API once every hour or day, rather than on every page load.

While caching is mandatory, relying solely on standard transients under high traffic creates a severe vulnerability known as a “cache stampede.”

Consider a high-traffic eCommerce store where an API transient expires. At that exact millisecond, 50 concurrent users land on the site. Because get_transient() returns false for all 50 workers simultaneously, every single one of those workers will independently execute wp_remote_get() to refresh the cache.

Instead of protecting the external API and your local server, you have just generated a massive, synchronized spike in outbound requests! If the third-party API responds slowly during this stampede, your worker pool instantly locks up, and the site crashes.

How to Prevent the Stampede: Transient Locking

To solve the cache stampede, we need to introduce a transient lock.

When the main cache expires, the very first PHP worker that notices the missing data will immediately set a temporary ‘lock’ transient (e.g., for 30 seconds). When the other 49 concurrent workers check the cache and see that it is empty, they will also see the lock. This tells them, “Someone else is already fetching the data!” Instead of piling onto the external API, those 49 workers will instantly return your fallback data, completely neutralizing the stampede.

function fetch_api_data_with_lock() {
    $cache_key = 'external_api_data';
    $lock_key  = 'external_api_data_lock';

    // 1. Try to get the cached data
    $cached_data = get_transient( $cache_key );
    if ( false !== $cached_data ) {
        return $cached_data; // Cache hit! Return immediately.
    }

    // 2. Cache is empty. Check if another worker is already fetching it.
    if ( get_transient( $lock_key ) ) {
        // The lock exists. Another process is currently hitting the API.
        // Return fallback data to prevent a stampede.
        return get_fallback_api_data();
    }

    // 3. No lock exists. Set the lock immediately for 30 seconds!
    set_transient( $lock_key, true, 30 );

    // 4. Safely fetch the data
    $response = wp_remote_get( 'https://api.external-service.com/v1/data', [
        'timeout' => 1.5,
    ] );

    // Handle failure
    if ( is_wp_error( $response ) ) {
        delete_transient( $lock_key ); // Clear lock so we can try again sooner
        return get_fallback_api_data();
    }

    $body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body, true );

    // 5. Success! Save the actual data for 1 hour and remove the lock.
    if ( $data ) {
         set_transient( $cache_key, $data, HOUR_IN_SECONDS );
    }
    delete_transient( $lock_key );

    return $data;
}

Defensive Routing: Tuning Your HTTP Requests

The first rule of defensive engineering is to never accept default configuration values blindly. By default, WordPress sets a 5-second timeout on HTTP requests made via wp_remote_get(). Five seconds is an eternity. If a worker hangs for 5 seconds on a high-traffic site, resource exhaustion is virtually guaranteed.

When communicating with external APIs on the frontend, you must lower your timeouts aggressively and handle the resulting errors gracefully using is_wp_error().

Here is how you can set up a defensive wrapper for an API call:

function fetch_defensive_api_data() {
    $url = 'https://api.external-service.com/v1/data';

    // Step 1: Lower timeouts aggressively
    $response = wp_remote_get( $url, [
        'timeout'   => 1.5, // 1.5 seconds max before failing fast
        'sslverify' => true,
    ] );

    // Step 2: Catch timeouts or network failures gracefully
    if ( is_wp_error( $response ) ) {
        // Log the error for internal auditing
        error_log( 'API Failure: ' . $response->get_error_message() );

        // Return fallback data instead of breaking the execution
        return get_fallback_api_data();
    }

    $body = wp_remote_retrieve_body( $response );
    return json_decode( $body, true );
}

function get_fallback_api_data() {
    // Provide safe, stale, or static default data to keep the UI intact
    return [
        'status' => 'offline',
        'items'  => [],
    ];
}

By reducing the timeout to 1.5 seconds, you guarantee that a failing API can only hold a PHP worker hostage for a brief moment, giving your server a fighting chance to recycle that worker and serve the next request.

Implementing the Circuit Breaker Pattern

Lowering timeouts protects your worker pool from long hangs, but it doesn’t stop your server from continuously hammering a broken or offline API. If an external service goes down for an hour, your server will still spend 1.5 seconds on every single page load trying to reach it.

To solve this, we can borrow a classic microservice architecture strategy: The Circuit Breaker Pattern.

The concept is straightforward:

  1. Closed Circuit: The API is functioning normally; requests flow through.
  2. Open Circuit (Tripped): The API has failed multiple times in a row. The circuit “trips,” and your code stops attempting to call the remote API entirely. It immediately returns fallback data without wasting server resources.
  3. Half-Open: After a cool-down period, the circuit allows a single request through to test if the external service has recovered.

We can implement a lightweight, highly effective circuit breaker natively in WordPress using the Object Cache or Transients API:

function fetch_api_with_circuit_breaker() {
    $circuit_status_key  = 'api_circuit_breaker_tripped';
    $failure_counter_key = 'api_failure_counter';

    // 1. Closed or Open? Check if the circuit is currently "Open" (Tripped)
    if ( get_transient( $circuit_status_key ) ) {
        // Circuit is open; fail fast immediately and return fallback data
        return get_fallback_api_data();
    }

    // 2. The circuit is Closed (or Half-Open). Attempt the remote request.
    $response = wp_remote_get( 'https://api.external-service.com/v1/data', [
        'timeout' => 1.5,
    ] );

    // 3. Handle a network failure or timeout
    if ( is_wp_error( $response ) ) {
        $failures = (int) get_transient( $failure_counter_key );
        $failures++;

        if ( $failures >= 3 ) {
            // Trip the circuit for 5 minutes. 
            // CRITICAL: We do NOT delete the failure counter here! 
            // We keep it so we can test a "Half-Open" state later.
            set_transient( $circuit_status_key, true, 5 * MINUTE_IN_SECONDS );
        } 

        // Always update the failure count, letting it live longer than the circuit trip time
        set_transient( $failure_counter_key, $failures, 1 * HOUR_IN_SECONDS );

        return get_fallback_api_data();
    }

    // 4. Success! If we get here, the API is healthy.
    // Clear the failure counter to fully reset to a "Closed" state.
    delete_transient( $failure_counter_key );

    $body = wp_remote_retrieve_body( $response );
    return json_decode( $body, true );

    // 5. Validate the payload to ensure it isn't malicious or malformed
    if ( ! is_array( $data ) || empty( $data ) ) {
        return get_fallback_api_data();
    }

    return $data;
}

With this architecture in place, if a third-party partner suffers an outage, your site will only try to talk to them 3 times. On the 3rd failure, the circuit trips. For the next five minutes, your site doesn’t spend a single millisecond waiting on that API, keeping your frontend lightning fast and completely insulated from the outage.

After those five minutes is where the Half-Open state comes in. Notice in the code that we don’t delete the failure counter when the circuit trips; we only delete it on a successful response. After the $circuit_status_key expires, the circuit becomes “Half-Open” and lets one single request through to test the API. If that request fails, the failure counter increments from 3 to 4, immediately tripping the 5-minute circuit again without forcing the server to wait for 3 new failures. If it succeeds, the counter is deleted, and the circuit fully closes.

Mind the Race Condition

The circuit breaker code above relies on get_transient() and set_transient() to count failures. While fine for standard setups, this introduces a race condition on extremely high-traffic sites.

Because transients are not atomic, if 10 users trigger an API timeout at the exact same millisecond, all 10 PHP workers might query the database simultaneously, read the failure count as 0, and all overwrite the count to 1. It might take longer than 3 actual failures to trip the circuit.

If your server runs a persistent object cache like Redis or Memcached, bypass the Transients API for the counter. Instead, use WordPress’s native wp_cache_incr() function. This performs a strictly atomic increment directly in the server’s RAM, guaranteeing perfectly accurate failure counting regardless of concurrent traffic.

Conclusion

Relying on external services is a necessity, but allowing those services to dictate your site’s availability is an architectural choice.

Wrapping HTTP requests in defensive patterns, such as reducing blocking timeouts, planning for transient cache stampedes, and implementing fail-fast circuit breakers. you ensure that a third-party disaster remains an isolated glitch on a specific feature, rather than a catastrophic site-wide crash.

The post Managing Third-Party API Bottlenecks in WordPress appeared first on Delicious Brains.

Automating Database Syncs with WP Migrate and WP-CLI

11 May 2026 at 19:45

Modern development workflows have mostly solved the file problem. We use Git to version our themes and plugins, and we use CI/CD pipelines to deploy those files to staging and production. But for many teams, the database remains a manual, high-stakes bottleneck.

Whether you are pulling production data down to a local environment for debugging or pushing a new ACF field structure up to staging, relying on manual SQL exports and imports is a recipe for disaster. It’s slow, it’s prone to human error, and it’s the most common way to break serialized data.

To reach true deployment maturity, you need to automate the database layer. That’s where WP Migrate’s integration with WP-CLI comes in.

Why wp db export Isn’t Enough

Many developers start by using the native wp db export and wp db import commands. While these are great for simple backups, they are dangerous for migrations between environments.

The primary culprit is serialized data. WordPress often stores complex data (like widget settings or ACF configurations) as serialized PHP objects. If your search-and-replace changes the length of a string (e.g., changing http://localhost to https://production.com), a standard SQL find-and-replace will break the serialization, and the data will simply vanish from the frontend.

Unlike standard SQL exports that treat the database like a flat text file, WP Migrate’s background logic handles search-and-replace at the PHP level. When the migration runs, the plugin identifies serialized data and temporarily unserializes it to perform the string replacement on the actual data structure. Once the strings are updated, it re-serializes the data and automatically recalculates the internal string-length counts before committing it to the destination database. This process ensures your metadata remains intact even when the new site URL has a completely different character count than the old one.

The Bridge: Migration Profiles

You can start firing off commands in the terminal at this point, but it’s probably better to create a Migration Profile first. Migration Profiles are a specialized feature provided by WP Migrate to manage complex configurations.

Migration Profiles are basically saved presets for your migration. In the WP Migrate UI, you define:

  • Which tables to include or exclude.
  • Specific find-and-replace pairs.
  • Whether to sync the Media Library or theme files.

By defining these in the UI first, you avoid the headache of passing dozens of complex arguments into a terminal command. Once saved, the CLI can trigger the entire logic of that profile using a single ID.

Selective Table Syncing: Protecting Production

The most significant risk in database automation is the push operation, when you move data from a lower environment (like Local or Staging) to the live Production server. If you push a full database that you’ve been working on for several days, you will overwrite the live site with your outdated local data, potentially wiping out every eCommerceorder or user registration that happened while you were developing.

This is where selective syncing becomes a mandatory safety measure. Instead of an “all or nothing” approach, WP Migrate’s integration with WP-CLI allows you to be surgical. In your Migration Profile, you should configure specific exclusions for transactional tables:

  • wp_users and wp_usermeta
  • wp_comments
  • wp_posts and wp_postmeta (specifically if you only want to sync settings/structures, not content)

By excluding these, you can perform a structural push that sends new ACF field groups or plugin configurations to production without the nightmare scenario of deleting customer data.

The Workflow: Push vs. Pull

In a professional pipeline, the direction of your migration depends on your goal.

Direction Command Best For… Risk Level
Pull wp migrate pull <ID> Refreshing staging with fresh production data. Low (Overwrites local/staging)
Push wp migrate push <ID> Deploying new ACF structures or settings to staging. High (Overwrites remote)

Automating with Secret Keys

WP Migrate uses secret keys for authorization. This means you don’t need to manage complex SSH tunnels just to move data. When setting up your CI/CD pipeline (like GitHub Actions), you should store these credentials as environment-scoped secrets within your CI/CD provider (like GitHub Actions or GitLab CI).

By scoping secrets specifically to the Production environment, you can implement protection rules, such as requiring a manual approval before the secrets are injected into a workflow. This ensures that a database push to your live site only happens when a senior team member has signed off on the deployment.

Real-World Implementation: GitHub Actions Snippet

Here’s how you might automate a Pull request to refresh a Staging site with Production data whenever a new release is tagged.

jobs:
  db-refresh:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger WP Migrate Pull via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.STAGING_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            # Navigate to the site root and trigger the saved profile
            cd /var/www/html
            wp migrate pull 5 --path=/var/www/html

In this example, the number 5 represents the specific ID of a Migration Profile created in the WP Migrate UI. Once you’ve identified your ID via the wp migrate profiles list command, the CLI takes it from there, automatically executing the authentication, the PHP-level search-and-replace, and the table exclusions you’ve already defined. This keeps your deployment script clean, as the heavy lifting of the configuration stays within the profile itself.

Conclusion

Manual migrations are basically technical debt. They eat up developer time and introduce unnecessary risk into your deployment cycle. By leveraging WP Migrate’s integration with WP-CLI, you move the database out of the manual task column and into your automated pipeline.

Whether you are syncing data for QA or deploying complex structural changes, using Migration Profiles and WP-CLI ensures that your environments stay in parity and your serialized data stays safe.

The post Automating Database Syncs with WP Migrate and WP-CLI appeared first on Delicious Brains.

Building Custom WP-CLI Commands for Massive Data Migrations

4 May 2026 at 17:38

Does this sound familiar? You need to update a custom field for 50,000 products or refactor user metadata across a massive membership site. You write a clean PHP script, drop it into a template or a hook, and hit refresh.

Thirty seconds later, you’re staring at a 504 Gateway Timeout.

The browser is a terrible place for data migrations. Between Nginx/Apache timeouts and PHP-FPM execution limits, it seems clear that web servers are designed to serve pages, not process massive datasets. In this situation, you need to step outside the browser and into the command line.

Why Your Scripts Are Crashing

The problem comes down to both timeouts and available memory. When you use get_posts() with 'posts_per_page' => -1, WordPress® attempts to load every single matching object into RAM at once. On a large site, this is a one-way ticket to a “Memory Exhausted” error.

Even if you process posts in batches, WordPress’s internal object cache grows with every record you touch. If you don’t clear it, your memory usage will climb steadily until the process dies.

The Solution: PHP Generators

Instead of loading a massive array into memory, we use PHP Generators. A generator allows you to iterate over data without building a massive array in RAM first. By using the yield keyword, the function provides one item at a time and “pauses” its execution until the next item is requested. When combined with a manual cache flush, this ensures it uses the same amount of RAM to process 1,000,000 posts as it does for 10.

Setting Up WP_CLI::add_command

WP-CLI is the standard for WordPress command-line interaction. By using WP_CLI::add_command(), we can register a custom tool that bypasses the web server entirely.

Building the Batching Loop

To keep things efficient, we create a generator to fetch IDs from the database. Then, we loop through that generator, processing each item one by one. By clearing the internal memory for every individual post and performing a global cache flush at regular intervals, we keep the server’s RAM usage completely flat from start to finish.

if ( defined( 'WP_CLI' ) && WP_CLI ) {
    WP_CLI::add_command( 'db-migrate', 'DB_Migration_Command' );
}

class DB_Migration_Command {

    /**
     * Updates product metadata in bulk.
     *
     * ## OPTIONS
     *
     * [--batch-size=<number>]
     * : How many posts to process before performing a global cache flush.
     * ---
     * default: 500
     * ---
     *
     * [--dry-run]
     * : Run the script without saving changes to the database.
     */
    public function products( $args, $assoc_args ) {
        global $wpdb;
        $dry_run    = isset( $assoc_args['dry-run'] );
        // Ensure batch size is at least 1 to avoid division by zero errors
        $batch_size = max( 1, (int) $assoc_args['batch-size'] );

        // 1. Get total count for the progress bar feedback
        $total_count = $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'" );
        $progress    = \WP_CLI\Utils\make_progress_bar( 'Updating Products', $total_count );

        // 2. The Safety Net: Start a SQL Transaction
        $wpdb->query( 'START TRANSACTION' );

        try {
            foreach ( $this->get_all_product_ids() as $index => $post_id ) {

                // Validate data before processing to prevent partial corruption
                if ( ! $this->validate_product( $post_id ) ) {
                    WP_CLI::warning( "Skipping Post ID: $post_id - Invalid status." );
                    continue; 
                }

                if ( ! $dry_run ) {
                    // Core function ensures hooks fire for search/caching plugins
                    update_post_meta( $post_id, '_new_meta_key', 'updated_value' );
                }

                $progress->tick();

                // 3. Memory Management: The "Scalpel"
                // Clear the internal cache for the post we just finished to keep RAM low
                clean_post_cache( $post_id ); 

                // 4. Memory Management: The "Sledgehammer"
                // Periodically clear the global object cache for massive datasets
                if ( 0 === ( $index + 1 ) % $batch_size ) {
                    wp_cache_flush(); 
                }
            }

            $progress->finish();

            // 5. Finalize or Rollback
            if ( ! $dry_run ) {
                $wpdb->query( 'COMMIT' );
                WP_CLI::success( 'Migration complete and saved to database!' );
            } else {
                $wpdb->query( 'ROLLBACK' );
                WP_CLI::log( 'Dry run complete. No changes were saved.' );
            }

        } catch ( Exception $e ) {
            // Undo everything if a critical error occurs
            $wpdb->query( 'ROLLBACK' );
            WP_CLI::error( 'Critical Error: ' . $e->getMessage() );
        }
    }

    /**
     * A Generator that yields post IDs one by one to save memory.
     * Replaces get_posts() with -1 which can cause memory exhaustion.
     */
    private function get_all_product_ids() {
        global $wpdb;
        $query = "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'";
        $ids   = $wpdb->get_col( $query );

        foreach ( $ids as $id ) {
            yield (int) $id; // "Pauses" execution to keep the array out of memory
        }
    }

    /**
     * Simple validation stub to ensure data integrity.
     */
    private function validate_product( $post_id ) {
        return get_post_status( $post_id ) === 'publish';
    }
}

Using WP_CLI\Utils\make_progress_bar() transforms a silent, terrifying script into a transparent process. It gives you real-time feedback and an estimated time of completion.

Managing the Object Cache

WordPress’s internal object cache grows with every record you touch. If you don’t clear it, your memory usage will climb steadily until the process dies. While wp_cache_flush() is the most straightforward way to prevent this, it can be a “nuclear option” on production sites using Redis or Memcached because it empties the cache for every visitor on the site.

Our script uses a hybrid approach. We use clean_post_cache() to surgically remove the memory used by a single post immediately after processing it. Then, we use wp_cache_flush() just once per batch to ensure the internal PHP memory remains lean without constantly hammering your persistent cache server.

Defensive Feedback & Transactions

When things go wrong, you want standard output. Use WP_CLI::success() for positive results and WP_CLI::warning() to notify the operator of minor data issues without killing the script.

Most importantly, the code utilizes SQL Transactions (START TRANSACTION, COMMIT, and ROLLBACK). This ensures atomicity, the “all or nothing” principle where either the entire migration succeeds perfectly or the database remains completely untouched. If a critical error occurs mid-process, the database automatically reverts to its original state. This is your safety net, ensuring you never have to deal with the nightmare of a production site stuck in a messy, “half-migrated” state.

Failure Resilience: Transactions and Logging

Crossing your fingers and hoping isn’t a good strategy when processing 50,000 records. If your script crashes halfway through, you are left with inconsistent data. By wrapping your loop in a SQL transaction, you ensure that changes are only finalized if the entire batch completes successfully. If a critical error occurs, the database can roll back to its original state.

For minor issues, like a single product missing a required field, don’t kill the script with WP_CLI::error(). Instead, use WP_CLI::warning() to alert the operator and log the offending ID to a text file for manual review later. This keeps the migration moving while ensuring no record is left behind.

The Workflow: Safety First with WP Migrate

Even with a --dry-run flag, running a migration script for the first time is stressful. This is where WP Migrate becomes an essential part of your toolbox.

  1. Pull to Local/Staging: Use WP Migrate to pull your production database to a local environment.
  2. Test the Command: Run your custom CLI command locally. Watch the progress bar and check for errors.
  3. Verify the Data: Inspect a few records to ensure update_post_meta() did exactly what you expected.
  4. Push or Deploy: Once verified, you can either run the command on production via SSH or push your local database back to staging for a final QA check.

The “Panic Button” Snapshot

Even with local testing and dry runs, never touch a production database without a quick backup. Right before you hit “Enter” on your custom migration command, run a manual export of your database via WP-CLI:

wp db export pre-migration-backup.sql

This means that even if the server crashes, you still have a timestamped file ready for an immediate wp db import. It’s a quick step that can save you hours of stress.

Conclusion

Massive data migrations don’t have to be a gamble. By moving your logic into a custom WP-CLI command and implementing a batching strategy, you bypass the limits of the web server and gain total control over your server’s resources.

Just hoping a script finishes won’t get you very far. Instead, build tools that provide feedback, manage memory, and offer a safe path to completion.

The post Building Custom WP-CLI Commands for Massive Data Migrations appeared first on Delicious Brains.

Delicious Brain Bytes: WordPress 7.0’s Beta Pivot, DE{CODE} 2026, and the 81 Flavors of Copilot

27 April 2026 at 15:54

In this issue of Delicious Brain Bytes, we look ahead to the era of the “Intelligent Web” with the opening of DE{CODE} 2026 registration, examine the technical hurdles pushing WordPress 7.0 back to a beta state, dive into the “Veils of Fate” RPG built with the Interactivity API, discuss the seismic shift in block themes with Brian Gardner, and much more!

DE{CODE} 2026 Registration is Open

WP Engine has officially opened registration for DE{CODE} 2026, its seventh annual virtual developer conference. Scheduled for May 6, 2026, this year’s theme explores the “Intelligent Web,” a new digital era where websites must serve both human audiences and the AI agents acting on their behalf. Across specialized Developer, Agency, and Marketer tracks, sessions will dive into how to create machine-readable content with ACF, master Generative Engine Optimization (GEO) to close AI citation gaps, and navigate the rise of “Zero-Click Commerce”.

This free virtual conference will be held live on May 6, with on-demand viewing available beginning May 7. You can register for free today and begin mapping out your sessions via the official North American or EMEA agendas.

WordPress 7.0 Finalizes May 20 Launch Following Reset

WordPress 7.0 has a new finish line of May 20, 2026. Following the unprecedented decision to return to a beta state to rebuild the Real-Time Collaboration database layer, the release squad has published an updated schedule to navigate the final stretch. To avoid breaking version-compare logic, the next pre-releases will retain the “Release Candidate” label but function as developmental resets: May 8’s RC3 will be treated as a new Beta 1, and May 14’s RC4 will act as a new RC1.

This version also brings a significant update to the roster of design tools per block, providing a cumulative lookup table of design supports added over the last ten WordPress releases. This updated guide tracks specific block features including Typography, Color, Layout, Shadow, and Background Image support, making it easier for developers to identify which core blocks now utilize these standardized tools. The 7.0 roster also highlights several new core blocks, including Math, Breadcrumbs, Icon, and Accordions, while the Verse block has been officially renamed to Poetry. Additionally, the method for handling Pattern Overrides has shifted from a hardcoded set of blocks to a dynamic, opt-in system that is now extended to custom blocks via the block bindings filter.

WordPress as Game Engine: “Veils of Fate” and the Interactivity API

Troy Chaplin has transformed a childhood obsession with “Choose Your Own Adventure” books into a sprawling digital RPG built entirely on WordPress. Known as Veils of Fate, the game features a branching narrative with over 100 scenes where player choices determine the direction of the story.

To create the fluid, app-like feel required for modern gaming, Troy utilized the Interactivity API to handle scene transitions without full page reloads. To manage the immense volume of data, Chaplin developed a custom CLI command to automate the import of scenes and quest metadata.

You can watch the full technical breakdown on Talk Devy to Me or begin your own journey at Veils of Fate.

The home page of Veils of Fate.

Call for Speakers: WordPress Accessibility Day 2026

WordPress Accessibility Day is returning for its 2026 global event, and the call for speakers is officially open. Scheduled for October 7–8, this free 24-hour virtual conference is seeking focused, specific presentations that explore the intersection of WordPress and inclusivity. Topics can range from first-hand perspectives on navigating the tech industry with a disability to technical deep-dives into React accessibility or the ethical implications of AI tools.

Following last year’s success, the event will utilize a pre-recorded format where speakers provide their 35–40 minute presentations in advance, followed by a live, real-time Q&A session with attendees. To support the community’s contributors, each accepted session will be awarded a $300 honorarium. If you have knowledge to share, be sure to submit your proposal before the June 9 deadline. Please note that to ensure authentic human expertise, the organizers will not accept any applications identified as AI-generated.

Brian Gardner Bets Big on Block Themes

In a recent episode of the WP Builds podcast, host Nathan Wrigley sat down with Brian Gardner, WP Engine’s Head of Community to discuss why he is “betting big” on the current seismic shift in WordPress theming. Gardner, a pillar of the community since 2006 and the co-developer of the Genesis framework, provides a unique perspective on how the platform has evolved from structured frameworks to the modern era of block-based design. A particularly forward-looking segment of the interview delves into the impact of AI on web design. For a deep dive into the business of modern theming, the role of flexible patterns versus traditional themes, and where the industry is headed in 2026, listen to the full interview on WP Builds.

Microsoft’s Copilot Problem: 81 Flavors and Counting

Don’t feel too bad if you’ve struggled to explain exactly what “Microsoft Copilot” is. Apparently even Microsoft isn’t entirely sure. According to a mapping project by Tey Bannerman, the tech giant now has at least 81 distinct products sharing the “Copilot” name. What started as an AI assistant has mutated into a confusing ecosystem of apps, platforms, an entire category of laptops, a dedicated keyboard key, and even something called “Microsoft Dragon Copilot”. Bannerman, who had to piece the list together from fragmented marketing materials because no official master list exists, created an interactive visualization to help users find a pattern in the branding chaos. Spoilers: he couldn’t find one either.

An attempt to map out the products named "Microsoft Copilot." The map shows dozens of entries.

Using MCP Servers in Concert: Smart Search AI, WordPress, and Cloudinary Integration

When building AI applications, you often face a fragmented data problem. Images live in Cloudinary, blog posts exist in WordPress, and each system has its own search. Users can’t ask “show me travel content” and get both images and posts—they have to search each system separately. This creates a poor experience and limits the possibilities of what can be built.

The Smart Search AI MCP solves this by acting as a single search layer across all of your content. It indexes data from multiple sources, including Cloudinary assets, WordPress posts, and anything else you manage. This ensures natural language queries return results no matter where the content lives. Instead of building separate search interfaces for each service, you build one chatbot that understands everything.

In this guide, Fran Agulto extends his previous Smart Search AI MCP tutorial, showing us how to orchestrate three MCP servers, Smart Search AI, WordPress, and Cloudinary, so that natural language prompts can discover content, create posts with images, and automatically index everything for future searches.

A view of a metadata page in a Cloudinary account.

The Developer’s Guide to wp_usermeta: Scaling Membership Sites

In the lifecycle of a membership site, there is a predictable point where the “My Account” page begins to lag and administrative user searches start to time out. Developers can spend hours optimizing wp_postmeta or the wp_posts table, but it’s the wp_usermeta table that is frequently the culprit behind these performance regressions.

As a site scales into tens of thousands of members, the architectural limitations of the WordPress user metadata system become apparent. Understanding how this table handles data and how it fails is critical for building a scalable membership platform.

In this article, we explore the architectural limitations of the wp_usermeta table, analyze the “array trap” of storing serialized data that forces expensive full table scans and discuss slow query patterns caused by unindexed meta values. Finally, we outline essential scaling strategies, including the use of individual meta keys, offloading database lookups through persistent object caching, and the implementation of custom SQL tables to ensure site stability as communities grow toward 100,000 members and beyond.

What’s the most interesting news you’ve come across recently? Pop by Twitter and let us know.

The post Delicious Brain Bytes: WordPress 7.0’s Beta Pivot, DE{CODE} 2026, and the 81 Flavors of Copilot appeared first on Delicious Brains.

Beyond `wp_enqueue`: Surgical Asset Management for High-Performance Sites

6 April 2026 at 19:10

A lot of WordPress® plugins follow the path of least resistance. They enqueue their CSS and JavaScript globally to ensure their features “just work” on every page. While this approach is safe for the developer, it’s less than ideal for site performance. Every unused byte of JavaScript adds to the browser’s execution time. This negatively impacts Total Blocking Time (TBT) and Largest Contentful Paint (LCP).

In this guide, we discuss how to move past basic script registration. We will look at how to interrogate the internal WordPress script queue and surgically remove the assets your visitors don’t actually need.

The Baseline: Contextual Loading

The first line of defense is ensuring your own code only loads when necessary. Don’t forget that the wp_enqueue_scripts hook is simply an action. You can wrap your enqueues in logic to restrict them to specific contexts.

Using Conditional Tags prevents scripts from loading where they aren’t needed. For example, if you have a heavy script that only runs on a specific “Contact” page, there’s no point in loading it everywhere else.

add_action( 'wp_enqueue_scripts', function() {
    // Only load the heavy Map script on the Contact page
    if ( is_page( 'contact' ) ) {
        wp_enqueue_script( 'google-maps-api', 'https://maps.googleapis.com/...', array(), null, true );
    }
});

Using is_page(), is_single(), or even has_block() allows you to implement “Just-in-Time” loading. This keeps your initial page weight low.

Peeking Inside the $wp_scripts Global

The real performance bottleneck often comes from third-party plugins. To stop them, you first have to identify their handles. You can spend a big chuck of time hunting through plugin source files if that’s what floats your boat, but it’s probably faster to just look at the internal state of the WordPress script manager.

WordPress uses the WP_Scripts class to manage the queue. During the page lifecycle, a global variable called $wp_scripts holds every registered and enqueued script.

Identifying the Bloat

You can interrogate this global object to see exactly which handles are enqueued for the current request. To use the following snippet, you can add it to a custom plugin used on a staging site or in a local development environment.

It is important to use the wp_print_scripts hook. This hook fires right before WordPress begins printing scripts into the header. This timing ensures that every plugin has finished its enqueuing logic, giving you a complete picture of the final queue.

Run in Local or Staging Environments

You should only run this code in a non-production environment, such as a local install or a staging site.

  • Local vs. Staging: While a local site is “safe,” a staging site is often superior for this audit because it perfectly mirrors your production plugin configuration and database state.

  • Why Not Production? This snippet outputs data directly into your site’s HTML source code. On a live site, this looks unprofessional to visitors and can reveal your specific plugin stack to malicious actors. Additionally, running debug logic on every page load adds unnecessary overhead to your server’s performance.

add_action( 'wp_print_scripts', function() {
    // Only run this if we are logged in as an admin to add an extra layer of privacy
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    global $wp_scripts;

    // Check if the WP_Scripts class has enqueued handles [cite: 6]
    if ( ! empty( $wp_scripts->queue ) ) {
        // Output the enqueued handles to the browser's JavaScript console
        echo '<script>console.log("Delicious Brains Audit - Enqueued handles: ' . implode( ', ', $wp_scripts->queue ) . '");</script>';
    }
});

By inspecting the queue property of the $wp_scripts object, you can find the exact strings needed to target specific plugin assets.

Programmatic Dequeuing: The Surgical Strike

Once you have identified your target handles, you can use wp_dequeue_script() to remove them. However, success depends a lot on priority.

In WordPress, hook priorities act like a waiting list where a higher number executes later. Since most plugins enqueue assets at the default priority of 10, you should hook into wp_enqueue_scripts with a much higher number (like 100) to ensure your removal logic runs after the plugin’s loading logic.

Example: Pruning Plugin Bloat

Suppose a “Reviews” plugin is loading a 150KB JavaScript file on your homepage. If reviews only exist on your product pages, you can strip that script everywhere else.

add_action( 'wp_enqueue_scripts', function() {
    // If we are on the Home page, remove the Reviews asset
    if ( is_front_page() ) {
        wp_dequeue_script( 'plugin-reviews-js' );
        wp_dequeue_style( 'plugin-reviews-css' );
    }
}, 100 ); // High number = runs later

For aggressive plugins that still manage to load, you can swap to wp_deregister_script(). This is a more permanent “nuclear” option that completely unbinds the handle from its source file for that specific request.

The Dependency Trap

Before you start pulling the plug on every script you see, you must check for dependencies. The wp_enqueue_script() function allows you to define a list of other scripts that must load first.

You’ll break the site’s functionality if you dequeue a script that other enqueued scripts depend on. The browser will throw “not defined” errors in the console. Always check the registered property within the $wp_scripts global to see the dependency array for a specific handle before removing it.

Conclusion

Advanced asset management is a game of subtraction. By auditing the WP_Scripts global and implementing high-priority conditional dequeuing, you can significantly reduce the weight of your frontend. This surgical approach ensures your site stays fast and lean without sacrificing the plugin functionality you need.

The post Beyond `wp_enqueue`: Surgical Asset Management for High-Performance Sites appeared first on Delicious Brains.

The Developer’s Guide to wp_usermeta: Scaling Membership Sites

24 March 2026 at 15:10

In the lifecycle of a membership site, there is a predictable point where the “My Account” page begins to lag and administrative user searches start to time out. Developers can spend hours optimizing wp_postmeta or the wp_posts table, but it’s the wp_usermeta table that is frequently the culprit behind these performance regressions.

As a site scales into tens of thousands of members, the architectural limitations of the WordPress user metadata system become apparent. Understanding how this table handles data—and how it fails—is critical for building a scalable membership platform.

The Architecture of wp_usermeta

Like the post meta and term meta tables, wp_usermeta follows the Entity-Attribute-Value (EAV) model. It is a vertical table designed to store an unlimited variety of data points for any given user.

umeta_id user_id meta_key meta_value
1 50 first_name Jane
2 50 last_name Doe
3 50 membership_level Gold

This flexibility is what makes WordPress powerful. However, this structure becomes expensive at scale. In a membership site with 50,000 users and 20 custom meta fields per user, the wp_usermeta table quickly grows to over a million rows. Every time you query for a user based on a specific attribute, MySQL must navigate this massive dataset.

The Array Trap: Serialized Data and Searchability

One of the most common architectural mistakes in membership site development is storing complex arrays in a single meta value. It is tempting to store all of a user’s “Subscription Preferences” or “Learning Progress” as a serialized array to keep the database row count low.

// The Performance Trap: Storing as an array
$preferences = array( 'email' => true, 'sms' => false, 'tier' => 'premium' );
update_user_meta( $user_id, 'member_preferences', $preferences );

While this works for simple data retrieval, it makes that data functionally invisible to the database for filtering. Because the meta_value column is a longtext field, it is not indexed. If you need to find every user where 'sms' => true inside that serialized array, MySQL cannot use an index. It must perform a “full table scan,” reading every single row in the metadata table and using a LIKE comparison.

On a large site, this pattern is a primary cause of timeout errors. If you need to query or filter by a specific piece of data, it must be stored as its own individual meta key rather than a value inside an array.

Slow Query Patterns in get_users()

When you use get_users() with a meta_query, WordPress performs a JOIN between the wp_users and wp_usermeta tables. This is a standard operation, but the performance cost increases exponentially as the tables grow.

The bottleneck usually occurs because the meta_value column is not indexed. While the meta_key is indexed, any query that checks the content of that key requires the database to scan the values manually.

If your membership site relies on complex filtering, such as finding users who joined after a certain date and have a specific custom role, you are likely triggering expensive queries that bypass the database’s most efficient paths.

Offloading with Persistent Object Caching

The most effective way to prevent wp_usermeta from becoming a bottleneck is to stop hitting the database entirely. This is where persistent object caching (via Redis or Memcached) becomes essential.

In a standard WordPress installation, user data is cached only for the duration of a single page load. A persistent object cache allows WordPress to store the results of user and meta lookups in the server’s RAM across multiple requests.

Persistent object caching ensures that once a user’s metadata is fetched once, it stays in the cache until it is explicitly updated. This is particularly impactful for:

  • Login Processes: Checking user credentials and roles.
  • Member Dashboards: Loading custom “My Account” data.
  • Administrative Searches: Navigating the “Users” screen in the WordPress backend.

By serving this data from RAM rather than the disk, you reduce the Time to First Byte (TTFB) and free up your PHP workers to handle actual visitor traffic instead of redundant database lookups.

Scaling Strategies for Large Sites

If your membership site is approaching 100,000 users, you may need to look beyond the default meta system.

  1. Use Individual Keys: Avoid serialized arrays for any data you intend to use in a filter or search.
  2. Audit Your Autoloaded Options: Be careful with plugins that store unique user data in the wp_options table with the autoload property set to ‘yes’. WordPress fetches every autoloaded option on every page request to populate the object cache. If this collective dataset becomes too large, it can significantly increase memory usage and slow down the initial database handshake. Maintaining a lean options table is a best practice for keeping your object cache healthy and responsive.
  3. Custom Tables: For highly specialized data that requires complex reporting, consider moving that data into a custom SQL table with dedicated indexes. This allows you to architect the schema specifically for your site’s unique query patterns.

A scalable membership site is built on the realization that user data is the most frequently accessed resource on your server. By prioritizing clean data structures and utilizing a persistent caching layer, you can ensure your platform remains performant as your community grows.

The post The Developer’s Guide to wp_usermeta: Scaling Membership Sites appeared first on Delicious Brains.

Scaling the REST API: Defensive Architecture for Custom Endpoints

16 March 2026 at 19:58

The WordPress® REST API is the primary bridge to modern frontend frameworks. However, default endpoints are generic by design. Custom endpoints require precise logic to avoid over-fetching data and exhausting server resources. A poorly architected custom endpoint can become a major performance bottleneck.

Building lean endpoints is essential for respecting the server’s PHP worker pool and memory limits. This ensures your API remains a performance asset rather than a liability. In this article, we examine how to architect high-performance custom endpoints by implementing selective data retrieval, efficient object caching, and network-level security.

How to Architect Lean Responses

One of the most effective ways to optimize an endpoint is to support the native _fields parameter. This allows the client to request only the specific data points it needs. This reduces the size of the JSON payload and the memory required to generate the response.

You should also avoid using standard WP_Query when it is not strictly necessary. WP_Query is a heavy operation that often triggers unnecessary metadata and taxonomy lookups. For surgical data retrieval, using $wpdb directly can significantly reduce memory overhead.

Implementing _fields Support

When registering a custom route, you can implement a filter to prune the response based on the client’s request.

add_action( 'rest_api_init', function () {
    register_rest_route( 'my-plugin/v1', '/data/', array(
        'methods'             => 'GET',
        'callback'            => 'get_custom_data',
        'permission_callback' => '__return_true',
    ) );
} );

function get_custom_data( $request ) {
    $data = array(
        'id'      => 101,
        'name'    => 'Performance Plugin',
        'version' => '2.1.0',
        'author'  => 'Delicious Brains',
    );

    // Check if the _fields parameter is present
    if ( isset( $request['_fields'] ) ) {
        $fields = wp_parse_list( $request['_fields'] );
        $data   = array_intersect_key( $data, array_flip( $fields ) );
    }

    return rest_ensure_response( $data );
}

The Caching Layer: Beyond the Database

You should almost never generate a complex API response on every single request. Using the Transients API allows you to store expensive results in an object cache. This prevents repeated hits to the database and significantly speeds up Time to First Byte (TTFB).

Understanding the Object Cache Layer

In a standard WordPress setup, transients are stored in the wp_options table. This means every time you fetch a transient, WordPress still has to perform a database query. An object cache layer changes this by storing that data in the server’s RAM instead of on the disk.

Keeping frequently accessed data in memory reduces the time it takes to access the database and keeps your server healthier by saving it from searching for the same information repeatedly.

Setting Up Your Own Caching Layer

If your hosting provider does not offer a managed solution, you can implement one yourself. The process generally involves two main components:

  1. Installing a Persistent Data Store: You will need to install a tool like Redis or Memcached on your server. These are specialized systems designed for high-speed, in-memory data storage.
  2. Connecting WordPress: Once the store is running, you need an object cache drop-in. This is a specialized PHP file (object-cache.php) placed in your wp-content folder that tells WordPress to route set_transient and get_transient calls to your new data store instead of the database.

Caching with Managed Hosting

Your host may already include solutions for this that require no manual configuration. If you are hosting with WP Engine, the object cache layer is enabled by default on all new environments. It can also be toggled manually within the WP Engine User Portal.

When using this managed layer, you must be mindful of the 1MB buffer size limit. Because the object cache stores data as a single long row, an oversized API response can cause the cache to reject the request. This can lead to a loop of failed requests and 502 Bad Gateway errors. To maintain a healthy environment, aim to keep your cached payloads under 800,000 bytes.

Security: Protecting the Gateway

A custom endpoint is a gateway into your database. It must be built with both a lock and a filter. Every route should include a permission_callback to ensure the requester is authorized to access the data.

You must also use validate_callback and sanitize_callback for every input argument. These functions protect your site against SQL injection and malformed data. For state-changing requests like POST or DELETE, ensure you are properly handling nonces or authentication headers to prevent unauthorized access.

Infrastructure Defense: Rate Limiting and Edge Security

Even a secure endpoint is vulnerable to API hammering. This is a scenario where an external script, bot, or malicious actor targets your custom endpoint with a high volume of requests. Because custom REST API requests are often uncacheable and resource-intensive, they can quickly exhaust your site’s PHP worker pool. This saturation prevents legitimate visitors from accessing the site, effectively resulting in a denial-of-service state.

To protect your server resources, you should look for security solutions that operate at the network edge rather than within WordPress itself.

Why Edge Security Matters

Traditional WordPress security plugins run as part of the application. This means every malicious request still has to be processed by your server before the plugin can block it. In contrast, edge security sits in front of your hosting environment. It acts as a high-performance barrier that filters traffic before it ever touches your WordPress install.

A robust edge strategy includes several key components:

  • Web Application Firewall (WAF): A WAF uses a set of rules to identify and block common exploits, such as SQL injection or cross-site scripting, at the network level.
  • DDoS Protection: High-capacity networks can absorb and mitigate large-scale distributed denial-of-service attacks that would otherwise overwhelm a single server.
  • Network-Level Rate Limiting: By identifying high-frequency requests from specific IP addresses, the edge layer can block API hammering before it reaches your PHP workers.

Strategic Implementations

If you are managing your own infrastructure, you can implement these protections using services like Cloudflare or specialized Nginx configurations. These tools allow you to set strict limits on how often a specific user or bot can hit your /wp-json/ endpoints.

Your host may include these protections as part of their service. For example, WP Engine offers Global Edge Security (GES). This managed solution leverages a global network to provide WAF protection and DDoS mitigation. Server resources are preserved for your actual users while malicious traffic is discarded at the edge.

Conclusion

Responsible API requests consider the health of the entire ecosystem, from the client’s data needs to the server’s available memory. Throughout this guide, we have explored how to move beyond basic endpoint registration toward a more defensive and performant architecture.

By implementing the _fields parameter and avoiding the overhead of standard WP_Query wrappers, you can ensure that your payloads remain lean and fast. We have also seen how the addition of an object cache layer is critical for preventing redundant database queries. Moving frequent lookups into memory reduces the strain on your database and improves response times across the board.

Finally, we discussed why securing the gateway to your database requires more than just code-level sanitization. True infrastructure defense involves shifting the burden of malicious traffic away from your PHP workers and toward the network edge. Combining these code-level optimizations with network-level rate limiting and WAF protection creates a robust system capable of handling high-traffic demands. This comprehensive approach ensures that your WordPress site remains stable, secure, and ready to scale.

The post Scaling the REST API: Defensive Architecture for Custom Endpoints appeared first on Delicious Brains.

Delicious Brain Bytes: Code Redefined, “Clippy” for WordPress, and Customizing Publication Checklists

9 March 2026 at 19:42

In this issue of Delicious Brain Bytes, we explore the human side of innovation in the Crafted with Code showcase, test-drive a nostalgic Clippy-style assistant in the WordPress® dashboard, and dive into WordPress.org’s new native Markdown support for AI agents. Plus, we check the pulse of the industry with the Admin Bar’s 2026 WordPress Professionals Survey, navigate changes in the FAIR project, and much more!

Crafted with Code: Where Tech Meets Human Judgment

The latest installment of the Crafted with Code series, Code Redefined: The Edge of Innovation, explores the intersection of purposeful technology and human judgment. In its sixth year, this showcase by WP Engine and the Webby Awards highlights that 30% of all Webby-recognized sites were built on WordPress®. This year’s “Code Redefined” theme explores how intelligence is embedded with intention across three standout projects:

  • Mozilla Builders (by Upstatement): Creating a digital home for the open-source AI community. By leveraging WordPress and WP Engine, the team built a site capable of handling massive traffic spikes while establishing Mozilla as a leader in the AI renaissance.
  • Farm Africa (by The Web Kitchen): Moving away from traditional charity tropes toward an energetic brand narrative. The modular block-based system helped drive a staggering 94% increase in online donations.
  • Skidmore, Owings & Merrill (by Code and Theory): A masterclass in performance for one of the world’s top architecture firms. The site manages a massive library of high-resolution architectural photography without sacrificing speed or stability.

Innovation in the AI era isn’t just about the tech you use, but the human choices that solve real-world challenges.

You can watch the full Crafted with Code playlist to see the behind-the-scenes stories of these award-winning builds.

Industry Pulse: The Admin Bar Launches 2026 WordPress Professionals Survey

For the fifth year in a row, the Admin Bar is benchmarking the “business side” of web development with its 2026 WordPress Professionals Survey.

Last year’s results from 1,200 pros revealed that Bricks was the only page builder gaining significant ground, and that agencies with a defined niche were 46% more likely to break six figures in revenue.

This year’s five-minute, anonymous survey dives deeper into AI integration and the evolving hosting landscape.

WordPress.org Launches Native Markdown Support for AI and Developers

WordPress.org has begun serving content in Markdown format, a major step toward becoming part of the agentic web. First announced on Make WordPress Meta, this update allows developers and AI agents to append .md to many WordPress.org URLs—including plugin directories and handbooks—to receive clean, structured data.

As noted in The Repository, this lowers token costs for LLMs and reduces AI hallucinations by providing “ground truth” documentation in a machine-readable format.

Decentralization at a Crossroads: FAIR Co-Founders Step Back

The Federated and Independent Repositories (FAIR) project is entering an uncertain chapter as co-founders Joost and Marieke de Valk officially step back to encourage broader community ownership. Since we noted the arrival of FAIR 1.0 and the security MVP with Patchstack, the project has sought to reduce reliance on a single central authority.

As reported in The Repository, the community is now weighing whether hosting companies and developers will maintain this decentralized infrastructure or if momentum will stall without its original advocates.

WordPress.org Now Rotates “Hidden Gems”

Following a community-led push, the WordPress.org Featured Plugins tab is now rotating “Hidden Gems” every two weeks. This shift mirrors the “quality over popularity” logic we explored in our coverage of the Hidden Gems plugin. By showcasing high-rated, low-install tools, the repository is providing independent developers a legitimate path to visibility based on merit rather than marketing budget.

Meet “Dewey,” the Clippy for WordPress

Nick Hamze has fulfilled a childhood dream by releasing “Dewey,” a Clippy-style assistant for the WordPress dashboard. Built to bring late-90s quirky energy to the modern CMS, Dewey offers “help” directly within the Block Editor. You can experience this nostalgic experimental design yourself by spinning up a live WordPress Playground instance using the project’s official blueprint.

Rethinking the Interface: Are We Asking the Right Questions?

In a thought-provoking new post, Jamie Marsland suggests the WordPress community is asking the wrong question about AI. Rather than wondering how to add AI buttons to existing tools, Marsland argues we should consider that users likely want AI instead of a complex software interface. He posits a paradigm shift where users simply talk to their website to make it “just work,” moving from traditional editing to natural, conversational creation.

Customizing WP Engine’s Newsroom Publication Checklist

In the publisher workflow, checklists are important to ensure that you don’t miss anything. Imagine how messy or unorganized things can get without checklists in your everyday life, let alone content you are writing for work.

In WordPress, WP Engine’s Newsroom features the Publication Checklist. It is a customizable quality-control tool that ensures all editorial standards are met before a story goes live.

The publication checklist helps you move away from time-consuming administrative content checks. Completely configurable to your requirements, the checklist flags missing items in real-time to editors before publishing, and gives customized suggestions to make sure your content meets everything you need it to.

In this article, Fran Agulto walks us through how to customize and use these features as well as integrate them with work management software.

YouTube cover image

Architecting Reliable Remote Requests with the HTTP API

Every time your code reaches out to an external API, you are introducing a point of failure that you do not control. Whether you are fetching a social feed, a weather widget, or processing a payment, your site’s performance is now tied to a third party.

A common mistake is treating a remote request like a local database query. If the external server is slow, your site becomes slow. If the external server is down, your site might crash or hang indefinitely. Professional WordPress development requires a defensive architecture that anticipates these failures. By using the WordPress HTTP API correctly, you can protect your site from external volatility.

In this article, we explore how to move beyond basic requests by architecting a defensive fail-safe strategy using the WordPress HTTP API to shield your site from external server volatility. By prioritizing rigorous error handling and strategic caching through the Transients API, you can ensure your site remains fast and stable even when third-party services stumble.

What’s the most interesting news you’ve come across recently? Pop by Twitter and let us know.

The post Delicious Brain Bytes: Code Redefined, “Clippy” for WordPress, and Customizing Publication Checklists appeared first on Delicious Brains.

Database Indexing: The Missing Manual for WordPress

2 March 2026 at 20:48

WordPress® is built to be a flexible application framework, but that flexibility comes with a trade-off in the form of a “one size fits all” database schema. For most sites, the default indexes provided by WordPress core are sufficient. However, as your site grows and your wp_postmeta and wp_options tables climb into the millions of rows, those standard indexes eventually hit a ceiling.

A site might feel fast on the frontend due to page caching, but a crawling dashboard or a ballooning slow query log indicates a database that is struggling to find data. Moving beyond standard tables requires an understanding of how MySQL indexing works and when to implement custom indexes to prevent full table scans.

How Indexing Works: The “Library” Analogy

In a database without an index, MySQL must perform a full table scan. This means it looks at every single row on the disk to find a match for your query. If you have 2.5 million rows of post meta, this process is incredibly slow and resource-intensive.

An index acts as a table of contents for your data. Instead of reading every page, MySQL uses a B-Tree structure to jump directly to the relevant information in logarithmic time.

This sounds great, but remember that there’s no such thing as a free lunch. While indexes dramatically speed up reads, they slightly slow down writes. Every time you insert or update a row, MySQL also updates the index file. On small tables, the performance gains are minimal and might even add unnecessary overhead. However, on large-scale sites, a missing index is often the primary cause of server bottlenecks.

The wp_options Bottleneck and the 1MB Buffer

The wp_options table is arguably the most common source of administrative slowness. WordPress is designed to query every row where autoload = 'yes' on every single page load to populate the object cache.

Depending on your hosting platform, these autoloaded values may be stored as a single row in the persistent object cache. This is where the 1MB buffer limit becomes a critical architectural guardrail. If the total size of your autoloaded data exceeds this 1MB limit, the cache layer may reject the request. This forces WordPress to repeatedly query the database for the same massive dataset, often resulting in a loop of failed requests and 502 Bad Gateway errors.

Even if you stay under the 1MB limit, a bloated options table makes primary index lookups less efficient. Keeping your wp_options table lean, ideally under 800,000 bytes, is essential for maintaining a healthy object cache and ensuring fast Time to First Byte (TTFB) for all requests.

Solving the wp_postmeta Nightmare

The wp_postmeta table is a “vertical” table that uses key/value pairs. By default, the meta_value column is not indexed because it uses a longtext data type.

If you run a meta_query that filters by meta_value, such as searching for all products within a specific price range, MySQL is forced to scan every single row of metadata. When your table reaches the millions, these queries can take seconds to execute.

The solution is often a partial (or prefix) index. Because you cannot index an entire longtext field, you can tell MySQL to index only the first $N$ characters of the column. This allows for significantly faster filtering while keeping the index size manageable.

Tools for Database Forensics

Before adding custom indexes, you must identify exactly which queries are causing the bottleneck.

  • Query Monitor is highly regarded for identifying slow queries directly within the WordPress UI. It highlights duplicates and expensive queries, allowing you to see exactly which plugin or theme component is responsible.

  • EXPLAIN: If you have a specific slow query, prefixing the SQL statement with EXPLAIN in a tool like phpMyAdmin or MySQL Workbench will reveal how MySQL intends to execute it. If the type column shows ALL, you have confirmed a full table scan is occurring.

  • For production environments where you want minimal overhead, the MySQL Slow Query Log records every statement that exceeds a defined time limit.

Conclusion: Stewardship of the Schema

Database indexing is not a “set it and forget it” task. As a site evolves, so do its data patterns. A query that was fast with 10,000 rows can become a site-killer at 1,000,000 rows.

Proper stewardship of the WordPress schema involves regular audits of your autoloaded data and the strategic application of custom indexes. By keeping your wp_options under the 1MB buffer and ensuring your meta queries are supported by indexes, you protect your site’s scalability and ensure a smooth experience for both visitors and administrators.

The post Database Indexing: The Missing Manual for WordPress appeared first on Delicious Brains.

Architecting Reliable Remote Requests with the HTTP API

24 February 2026 at 16:37

Every time your code reaches out to an external API, you are introducing a point of failure that you do not control. Whether you are fetching a social feed, a weather widget, or processing a payment, your site’s performance is now tied to a third party.

A common mistake is treating a remote request like a local database query. If the external server is slow, your site becomes slow. If the external server is down, your site might crash or hang indefinitely. Professional WordPress® development requires a defensive architecture that anticipates these failures. By using the WordPress HTTP API correctly, you can protect your site from external volatility.

Beyond the Basics: The Anatomy of wp_remote_get()

The functions wp_remote_get() and wp_remote_post() are high-level wrappers for the WP_Http class. They provide a standardized way to make requests without worrying about whether the server is using cURL or temporary streams.

When you make a request, WordPress returns a response object. This object is an associative array containing several key pieces of data:

  • headers: This includes the response headers from the external server.
  • body: This is the actual payload, which is usually a JSON string or XML.
  • response: This contains the HTTP response code, such as 200 for success or 404 for not found.
  • cookies: Any cookies returned by the destination server are stored here.

Defensive Programming: Handling Fail States

A robust integration must account for the fact that things will go wrong. You should never assume the data you requested is actually there.

First, you must check for a WP_Error. This happens if the request fails to even reach the server due to a DNS issue or a connection timeout. Always wrap your request in the is_wp_error() check.

Second, you must verify the HTTP response code. A request can succeed technically but still return a 500 Internal Server Error. Use wp_remote_retrieve_response_code() to ensure you received a 200 OK before proceeding.

Finally, validate the body. If you expect JSON, use json_decode() and check that the resulting data structure is what you expect. Attempting to iterate over a null or empty object is a frequent cause of fatal errors.

Performance Tuning and Strategic Timeouts

The default timeout for a WordPress remote request is 5 seconds. In a frontend user experience, 5 seconds is an eternity. If an API takes that long to respond, your user has likely already left the page.

You should use the 'timeout' argument to fail fast. If a non-essential weather API doesn’t respond in 1.5 seconds, it is often better to show a default icon than to keep the user waiting.

For heavy requests that don’t need to happen in real-time, consider moving them to a background process. Using WP-Cron allows you to fetch data without forcing the visitor to wait for the external server to respond.

Caching the Results

This is where the HTTP API connects to our previous deep dive into the Art of the WordPress Transient. You should almost never make a remote request on every page load. Instead, implement a caching workflow.

The process begins by checking for a valid transient in the object cache. If the data is missing or has expired, you then perform the remote request. If that request is successful, you store the result in the object cache for a set duration.

On platforms like WP Engine, enabling object caching ensures database and API results are stored in RAM for near-instant retrieval. This prevents your site from being blocked by external APIs for making too many repeated requests. While the system primarily serves fresh data, you can also utilize the Transients API to serve cached results as a fallback if a remote service becomes temporarily unavailable.

Conclusion

A reliable remote request is one that knows how to fail gracefully. By combining the WordPress HTTP API with intelligent error handling and persistent object caching, you create a buffer between your site and the unpredictable nature of external servers. This architecture ensures your site remains fast and stable, regardless of what is happening elsewhere on the web.

The post Architecting Reliable Remote Requests with the HTTP API appeared first on Delicious Brains.

Taming the Heartbeat API: Preventing `admin-ajax.php` Overload

17 February 2026 at 16:53

When it comes to WordPress® performance, we often focus on the big metrics: page load speed, database query optimization, and asset minification. However, there is a silent pulse running in the background of every WordPress installation that can, under the right conditions, bring even a robust server to its knees.

This pulse is the WordPress Heartbeat API.

Introduced in WordPress 3.6, the Heartbeat API provides a way for the browser to communicate with the server in real-time while a user is logged into the dashboard. It manages essential features like session concurrency, auto-saving posts, and post locking, ensuring that two editors don’t accidentally overwrite each other’s work.

While these features are vital for a collaborative environment, the Heartbeat API’s default behavior isn’t always optimized for high-concurrency sites. If left unmanaged, it can lead to exhausted server resources and impacts on site stability.

Anatomy of a Heartbeat Request

The Heartbeat API functions by sending a POST request to admin-ajax.php at regular intervals (usually every 15 to 60 seconds). The journey of a single “pulse” looks like this:

  1. Browser Trigger: The JavaScript on the client side initiates a request.
  2. Server Contact: The request hits admin-ajax.php.
  3. WordPress Bootstrap: Even though it’s a background request, WordPress must perform a full bootstrap—loading the core, active plugins, and the theme—to process the request.
  4. Response: The server sends back data (like the “post locked” status) to the browser.

The critical issue here is that Heartbeat requests are uncacheable. Because they are POST requests sent to the administrative backend, they bypass standard page caching. Every single pulse requires a dedicated PHP worker to process.

On a site with a single editor, this is negligible. The math changes rapidly when it’s a site with 50 concurrent users, whether they are editors in a newsroom or students in a learning management system. Fifty users with the dashboard open can generate hundreds of uncacheable requests per minute, saturating the server’s capacity.

Diagnosing the Impact

Identifying a “Heartbeat Storm” starts with the server logs. If your access logs are filled with repetitive POST requests to /wp-admin/admin-ajax.php with the action heartbeat, the API is likely the culprit.

Beyond logs, this overhead manifests as a drain on PHP workers. PHP workers are the engines that process the PHP code on your site. Since a worker is “occupied” for the duration of every Heartbeat pulse, a high volume of these background tasks leaves fewer workers available to serve actual frontend traffic to your visitors.

Programmatic Throttling: The heartbeat_settings Filter

You do not necessarily need to disable the Heartbeat API entirely.Doing so would break useful features like auto-save. Instead, another approach is to throttle the interval.

By default, the “pulse” happens every 15 seconds when you are editing a post. You can use the heartbeat_settings filter to change this interval to the maximum allowed (60 seconds), significantly reducing the load.

/**
 * Throttle the Heartbeat API to 60 seconds.
 */
add_filter( 'heartbeat_settings', function( $settings ) {
    $settings['interval'] = 60; // Set to the maximum allowed 60 seconds
    return $settings;
});

Contextual Control

In some cases, you may want to disable the Heartbeat API on specific parts of the site where it serves no purpose. For instance, there is rarely a need for the heartbeat to run on the frontend of the site for non-administrative users.

You can selectively deregister the script based on the screen or the user’s capabilities:

/**
 * Disable Heartbeat on the frontend unless a user is editing a post.
 */
add_action( 'init', function() {
    if ( ! is_admin() ) {
        wp_deregister_script( 'heartbeat' );
    }
});

Architecting for Stability

Managing the Heartbeat API is a key component of site reliability engineering for WordPress. By slowing down the background pulse, you ensure that your server’s resources—specifically its PHP workers—are prioritized for the most important task: serving your content to your audience.

Standardizing these throttles in your theme or a core functionality plugin allows for a more predictable server load, preventing administrative activity from ever becoming a bottleneck for site performance.

The post Taming the Heartbeat API: Preventing `admin-ajax.php` Overload appeared first on Delicious Brains.

The Art of the WordPress Transient: Performance, Persistence, and Database Bloat

10 February 2026 at 18:48

In the hierarchy of WordPress® data storage, transients often occupy a misunderstood middle ground. They aren’t quite as permanent as options, yet they aren’t as ephemeral as a standard PHP variable.

The Transients API is designed to store cached data with an expiration time. It is the go-to tool for developers looking to cache expensive operations like remote API calls and complex database queries. It ensures that a single slow request doesn’t degrade the experience for every subsequent visitor.

However, beneath the simple set_transient() wrapper lies a complex relationship with the WordPress database that, if left unmanaged, can lead to significant performance bottlenecks.

Under the Hood: The wp_options Forensics

To understand how transients affect a site, we must look at how they are physically represented in the database. When a transient is created using the standard WordPress configuration, it doesn’t just create one row in the wp_options table; it creates two.

Consider the following command:

`set_transient( 'github_api_data', $value, HOUR_IN_SECONDS );`

In the wp_options table, WordPress will generate:

  1. _transient_github_api_data: This row contains the actual serialized value of the data.
  2. _transient_timeout_github_api_data: This row contains a Unix timestamp representing the moment the data should expire.

The logic follows a simple mathematical check every time get_transient is called to determine if the data is still valid:

$$\text{is\_expired} = (\text{current\_time} > \text{timeout\_timestamp})$$

If this calculation evaluates to true (meaning the clock has passed the expiration point), WordPress deletes the expired rows and returns false to the application. This false response serves as the signal to the developer that it is time to refresh the data and set the transient once again.

However, there’s a hidden danger here. It lies in how WordPress handles the autoload flag for these rows. While transients with an expiration, like our example above, are not autoloaded, any transient set without an expiration is automatically set to autoload: yes. This means every time a page is requested, those rows are pulled into memory, even if the current page doesn’t need them. If a developer inadvertently creates numerous non-expiring transients, this global overhead can quickly exceed the 1MB buffer limit of the object cache.

This means every time a page is requested, these rows are loaded into memory by the WordPress core, regardless of whether that specific page actually needs the GitHub API data. On a site with hundreds of transients, this global overhead begins to chip away at PHP memory limits.

The Garbage Collection Problem

A common misconception is that WordPress has a background process, a sort of garbage collector, that automatically deletes expired transients.

In reality, an expired transient is only deleted when it is specifically requested via get_transient(). If a plugin is deactivated, or if a developer changes the name of a transient key, the old “expired” rows may sit in the wp_options table indefinitely.

On high-traffic sites or those using dynamic naming conventions, this can result in thousands of orphaned rows. This bloat increases the size of the database index and slows down every single query targeting the wp_options table.

Manual Cleanup: Identifying and Removing Bloat

For sites with significant transient bloat, you can use the following SQL query to safely remove all expired transients from the wp_options table. This is particularly useful for cleaning up “orphaned” rows left behind by deactivated plugins or old dynamic keys.

DELETE a, b FROM wp_options a
JOIN wp_options b ON a.option_name = REPLACE(b.option_name, '_transient_timeout_', '_transient_')
WHERE b.option_name LIKE '_transient_timeout_%'
AND b.option_value < UNIX_TIMESTAMP();

This works by identifying the “timeout” row (_transient_timeout_) and checks if the stored Unix timestamp is older than the current time. It then joins the corresponding data row (_transient_). Finally, it deletes both rows simultaneously, ensuring your database stays lean and indexed properly.

Scaling with WP Engine Object Caching

One way to address the issue of transient bloat is to leverage the object cache layer provided by your hosting environment. On the WP Engine platform, object caching is a primary tool used to improve site stability, speed, and scalability.

Unlike standard WordPress installations where you might need to configure this manually, object caching is enabled by default on all new WP Engine environments. This layer acts as a specialized storage area that sits between your site and the database. When an operation like a transient request is made, the server first checks this caching layer for a result. If the data is found, it is served immediately, completely bypassing the need for a database query.

This greatly reduces the load on your server, but it’s not a bottomless storage solution. It requires a clear understanding of how your site uses transients and options, particularly those stored as autoloaded data.

The Benefits and Constraints of Object Caching

Implementing an object cache layer offers several technical advantages for high-traffic sites:

  • Reduced Database Latency: By storing the results of repeated queries, the server significantly reduces the time spent accessing the database.

  • Improved Server Health: The server stays “healthier” because it spends less energy and fewer resources searching the database for the same information repeatedly.

  • Intelligent Memory Management: The object cache does not clear on a fixed schedule. Instead, it uses a “Least Recently Used” (LRU) algorithm to automatically identify and remove older query results only once its allocated storage space is full.

The 1MB Buffer Caveat

Despite these benefits, developers must be mindful of the 1MB buffer size limit. Object caching stores autoloaded values as a single long row. If your transients and other autoloaded data combined surpass what the cache can handle, the system will reject the request.

This rejection can trigger a dangerous loop. WordPress requires the data to load the page and will immediately send the request again, eventually resulting in a 502 error on the site. To maintain a healthy environment, it is recommended that all autoloaded data stays below 800,000 bytes. If you encounter persistent 502 errors after adding new transients, temporarily disabling object caching may be necessary while you identify and reduce the volume of autoloaded data.

Developer Best Practices

To maintain a healthy balance between performance and persistence, consider these updated standards for your development workflow:

  • Strict Namespacing: Use a consistent, unique prefix for all transient keys to make them easily identifiable during a database audit or when debugging.

  • The “Get/Check/Set” Pattern: Always handle the “false” return of a missing transient gracefully using the strict identity operator (=== false). Because a transient might store a “falsy” value like an empty string or the number 0, a loose check could trigger an unnecessary and expensive data refresh. Remember that a transient is a “best-effort” cache. Your code should never be written with the assumption that the data will be there when requested.

  • Key Length Management: Keep your transient keys under 172 characters. WordPress appends prefixes like _transient_timeout_ to your key before saving it to the database; if the total string exceeds the character limit of the option_name column, the transient may fail to save or retrieve correctly.

  • Mind the Expiration: Avoid setting excessively long expirations for data that changes frequently. Shorter, more aggressive caching windows (e.g., 5 to 15 minutes) are often safer for maintaining site consistency and reducing the risk of serving stale content.

Conclusion

Transients are one of the most powerful tools in the WordPress developer’s arsenal, but they are not a “set it and forget it” solution. By understanding the database forensics behind the API and leveraging persistent object caching, you can ensure that your cache stays warm and your database stays lean.

The post The Art of the WordPress Transient: Performance, Persistence, and Database Bloat appeared first on Delicious Brains.

WP Offload Media 3.3 Released: Modern Standards, Global Regions, and Enhanced Stability

3 February 2026 at 16:50

We are excited to announce the release of WP Offload Media 3.3! This release focuses on modernizing our codebase to support the latest server environments, expanding our global footprint with new storage regions, and refining the user experience with key stability improvements.

As WordPress and PHP continue to evolve, we are committed to ensuring WP Offload Media remains the most reliable solution for offloading your assets. Let’s dive into what’s new.

🚀 Embracing Modern Standards: PHP 8.1+ and WordPress 5.9+

To deliver the best performance and security, we have updated the minimum requirements for the plugin. Starting with version 3.3, WP Offload Media now requires PHP 8.1+ and WordPress 5.9+.

By raising these minimums, we can leverage more efficient code and ensure compatibility with the latest technologies. This release introduces full compatibility for PHP 8.4 and PHP 8.5, as well as support for WordPress 6.9.

Additionally, we have updated the underlying AWS PHP SDK to v3.360.1 along with other critical PHP and JS dependencies, ensuring your connection to Amazon S3 remains secure and robust.

🌍 Expanded Global Reach

For users targeting specific geographic audiences, latency matters. We have added support for several new selectable regions across our three major providers:

  • Amazon S3: Asia Pacific (Taipei) and Asia Pacific (New Zealand).
  • Google Cloud Storage: North America (Querétaro) and Europe (Stockholm).
  • DigitalOcean Spaces: Atlanta (ATL1).

These additions allow you to store your media closer to your visitors in these regions, further improving load times.

And even if you use a CDN to provide faster media access to all your site visitors worldwide, being able to use a bucket nearer to your site’s server improves media offload performance.

💾 Improved Metadata Integrity

For those who frequently move media between the cloud and their local server, we’ve made an important improvement to data preservation. Previously, when an item was downloaded from the cloud back to the server, the file size attachment metadata value could be removed.

In version 3.3, this value is no longer removed during the download process, ensuring your attachment metadata remains complete and accurate regardless of where the file currently lives.

🛠️ Integrations and UI Fixes

We are always working to ensure WP Offload Media plays nicely with the rest of the WordPress ecosystem. This release fixes a specific conflict with Rank Math SEO, where deleting an item via the Media Library’s grid mode would fail. This functionality has been restored.

We also polished the user interface on the “Edit Media” page. Now, when you toggle the Public/Private access status of a file, the “Download File” link updates dynamically to reflect the change immediately, without requiring a page refresh.

🤩 And More…

  • Robustness: We’ve added protection against invalid values being passed to the core the_post action, preventing potential crashes.

  • Legacy Support: The legacy file size upgrade routine has been patched so it no longer throws errors if attachment metadata is missing.

For a full breakdown of changes, you can view the changelog.

Are you ready to update? As always, we recommend backing up your site before performing any major updates. Let us know what you think of the new changes in the comments below!

The post WP Offload Media 3.3 Released: Modern Standards, Global Regions, and Enhanced Stability appeared first on Delicious Brains.

Debugging WP-Cron With WP-CLI

3 February 2026 at 20:17

It’s a common situation. You schedule a backup for 2 a.m., but when you log in the next morning, the file isn’t there. Or perhaps a scheduled post missed its publication window, leaving you with a “Missed Schedule” error.

The root cause is often the WordPress cron system. Unlike a standard system cron that runs on a strict clock, WP-Cron is a pseudo-cron. It relies on page visits to trigger scheduled tasks. If no one visits the site, the tasks don’t run. If a visitor arrives while a heavy task is pending, their page load might hang while WordPress processes the queue in the background.

Debugging this via the WordPress dashboard is often frustrating. Installing a plugin just to view your cron events adds unnecessary bloat. A more direct and reliable method is to use the command line.

WP-CLI provides immediate visibility into the scheduler and, more importantly, allows you to force-run events to see if they fail.

Gaining Visibility

The first step in debugging is seeing what is actually in the queue. The default dashboard gives you no insight into this, but one command reveals the entire schedule.

Run the following command in your terminal:

wp cron event list

This outputs a table with four key columns: hook, next_run_gmt, next_run_relative, and recurrence.

The most important column for debugging is next_run_relative.

  • If it says “10 minutes” or “1 hour,” the event is scheduled for the future.
  • If it says “now”, “1 hour ago”, or “Yesterday”, the event is stuck.

A “stuck” event usually means one of two things: either the site hasn’t had any traffic to trigger the runner, or the PHP script attempted to run but crashed silently.

The Magic Fix: Force Running Events

Waiting for a suspect task to run naturally is inefficient. You need to see the error output immediately.

You can force any event to run right now, regardless of its schedule, using the run command:

wp cron event run <hook_name>

For example, if your backup hook is named my_daily_backup, you would run:

wp cron event run my_daily_backup

When WP-Cron runs normally (via a page visit), PHP errors are often suppressed or hidden in a log file you might not be checking. Fatal errors are output directly to your terminal when you run it via WP-CLI.

If the script is running out of memory or hitting a PHP timeout, the command line will tell you instantly.

Clearing the Backlog

If you manage a site that has been offline or neglected, you might find dozens of overdue tasks clogging the queue. Rather than running them one by one, you can force WordPress to process all overdue events at once:

wp cron event run --due-now

Cleaning Up the Junk

Over time, the wp_options table can accumulate orphaned cron events. These are scheduled tasks left behind by plugins that were deactivated or deleted incorrectly. They don’t break the site, but they do clutter the database and the cron list.

To delete a specific event:

wp cron event delete <hook_name>

Be careful not to delete core WordPress hooks (like wp_scheduled_delete or wp_version_check). Focus only on hooks clearly named after plugins you no longer use.

Alternative: Disabling the Default WP-Cron

For high-traffic sites, or sites where timing is critical, relying on page visits to trigger tasks is often insufficient. In these cases, it’s common to disable the default behavior and replace it with a system cron.

This involves two steps. First, you disable the trigger in wp-config.php:

define('DISABLE_WP_CRON', true);


This stops WordPress from checking for scheduled tasks on every page load, which can improve page load speed for users.

However, once this is disabled, nothing will run until you set up an alternative trigger. You must add an entry to your server’s system crontab to call WP-CLI every minute.

Important: Do not run this as the root user. WP-CLI limits root execution for security reasons. Instead, add this line to the crontab of your web server user (often www-data) or your specific hosting user:

* * * * * /usr/local/bin/wp cron event run --due-now --path=/var/www/yoursite/ > /dev/null 2>&1


There are three key changes in this command compared to a standard manual run:

  1. Full Path: We use /usr/local/bin/wp because system crons run in a minimal environment and might not know where the wp command is located otherwise.
  2. Path to Site: The --path flag ensures WP-CLI executes within the correct WordPress installation.
  3. Silencing Output: The > /dev/null 2>&1 at the end prevents the server from emailing you a notification every single minute that the task ran successfully.

This configuration ensures that scheduled tasks run precisely on time, regardless of whether anyone is visiting the website.

Conclusion

WP-Cron shouldn’t be viewed as a “black box” that developers cross their fingers and hope works. Shifting your workflow to the terminal turns that black box into a transparent queue. Using wp cron event list and run allows you to diagnose issues in seconds rather than days, ensuring your backups, emails, and scheduled posts happen exactly when they are supposed to.

The post Debugging WP-Cron With WP-CLI appeared first on Delicious Brains.

The Anatomy of theme.json: A Developer’s Cheat Sheet

27 January 2026 at 19:04

For a long time, the logic of a WordPress® theme lived primarily in functions.php. If you wanted to add support for a custom logo, wide alignment, or editor styles, you reached for add_theme_support(). It was a reliable, albeit often cluttered, way to manage theme configuration.

With the advent of Block Themes and Full Site Editing (FSE), that responsibility has shifted. Now, theme.json is the central nervous system of a modern WordPress theme. It controls the block editor, defines global styles, and manages the presets available to content creators.

It is a massive JSON object that can feel intimidating at first glance. However, once understood, it offers a level of granular control over what clients can and cannot do that was difficult to achieve in the classic PHP era.

Here is a breakdown of the file’s anatomy and how to use it to architect better, more maintainable themes.

The Schema (The Developer’s Best Friend)

One of the biggest hurdles when working with theme.json is remembering the hierarchy. Is it typography.fontSizes or typography.fontFamilies? Does color go inside settings or styles?

The most effective workflow improvement is to define the $schema property at the very top of the file.

{
    "$schema": "https://schemas.wp.org/trunk/theme.json",
    "version": 3
}

This is not just metadata. When using a modern code editor like VS Code, this line enables IntelliSense. It provides autocomplete suggestions for valid properties and flags errors immediately if a key is nested incorrectly. It turns the file from a guessing game into a documented API.

Settings (Building the Guardrails)

The settings section is where you define the rules of the theme. This is where you register palettes, font sizes, and layout constraints.

Crucially, this is also where you lock down the UI. For agencies and freelancers delivering sites to clients, theme.json is the most efficient way to prevent “design drift.” By explicitly disabling custom pickers, you ensure that content creators can only use the brand colors and typography you have defined.

Here is a configuration that enforces a strict design system:

"settings": {
    "color": {
        "custom": false,
        "customGradient": false,
        "palette": [
            {
                "slug": "primary",
                "color": "#2C3E50",
                "name": "Midnight Blue"
            },
            {
                "slug": "secondary",
                "color": "#E74C3C",
                "name": "Alizarin"
            }
        ]
    },
    "typography": {
        "customFontSize": false,
        "fontFamilies": [
            {
                "fontFamily": "Helvetica, Arial, sans-serif",
                "name": "Sans Serif",
                "slug": "sans"
            }
        ],
        "fontSizes": [
            {
                "slug": "normal",
                "size": "1rem",
                "name": "Normal"
            },
            {
                "slug": "large",
                "size": "1.5rem",
                "name": "Large"
            }
        ]
    },
    "layout": {
        "contentSize": "800px",
        "wideSize": "1200px"
    }
}

By setting properties like custom and customFontSize to false, the color pickers and custom input fields disappear from the WordPress editor. The user is left with only the pre-approved options defined in the palette and fontSizes arrays.

Styles (CSS Without the CSS)

The styles section effectively replaces the traditional style.css for global defaults. When WordPress renders the page, it reads this JSON object and generates the necessary CSS variables and classes automatically.

Note: While theme.json handles the visual styling, your theme must still contain a style.css file in the root directory. WordPress relies on the header comment in this file to identify the Theme Name, Author, and Version. You can leave the file empty of actual CSS rules, but the file itself is mandatory for the theme to appear in the WordPress dashboard.

This structure mimics the CSS cascade. You begin by defining the root defaults (usually applied to the <body>) and then move on to specific elements.

"styles": {
    "color": {
        "background": "var(--wp--preset--color--primary)",
        "text": "#ffffff"
    },
    "typography": {
        "fontFamily": "var(--wp--preset--font-family--sans)",
        "fontSize": "var(--wp--preset--font-size--normal)",
        "lineHeight": "1.6"
    },
    "elements": {
        "link": {
            "color": {
                "text": "var(--wp--preset--color--secondary)"
            },
            ":hover": {
                "color": {
                    "text": "#ffffff"
                },
                "typography": {
                    "textDecoration": "underline"
                }
            }
        },
        "h1": {
            "typography": {
                "fontSize": "3rem",
                "fontWeight": "700"
            }
        }
    }
}

Notice the use of CSS Variables (e.g., var(--wp--preset--color--primary)). WordPress automatically generates these variables based on the presets defined in the settings section. Using these variables ensures that if a hex code is changed in the palette, it updates globally across the entire site.

Block-Specific Overrides

A common challenge in theme development is applying distinct styles to specific blocks without writing highly specific CSS selectors that are hard to override later.

theme.json handles this hierarchically. You can drill down into specific blocks to override the global defaults.

For example, if you want all Buttons to have a specific border radius, or the Code block to use a monospaced font family that differs from the body text:

"styles": {
    "blocks": {
        "core/button": {
            "border": {
                "radius": "50px"
            },
            "color": {
                "background": "var(--wp--preset--color--secondary)",
                "text": "#ffffff"
            }
        },
        "core/code": {
            "typography": {
                "fontFamily": "\"Courier New\", Courier, monospace",
                "fontSize": "0.9rem"
            },
            "color": {
                "background": "#f0f0f0",
                "text": "#333333"
            }
        }
    }
}

This approach keeps the styling logic encapsulated. The styles for the button block are attached to the block definition itself, ensuring they load only when a button is actually present on the page.

The Future of Theme Configuration

The shift to theme.json represents a move toward standardization. It reduces the reliance on loose PHP functions and massive CSS files, replacing them with a structured configuration that WordPress understands natively.

For developers, the initial learning curve involves memorizing the structure (or using the schema to do it for you). But the long-term benefit is a theme that is more performant, easier to maintain, and safer to hand off to clients.

The post The Anatomy of theme.json: A Developer’s Cheat Sheet appeared first on Delicious Brains.

Delicious Brain Bytes: WordPress 7.0 Roadmap, Gutenberg 22.3, and the Rise of the Agentic Web

20 January 2026 at 16:32

In this issue of Delicious Brain Bytes, we explore the brand-new Gutenberg 22.3 features, look ahead to the WordPress® 7.0 release and its updated PHP requirements, discuss WP Engine’s strategic acquisition of Big Bite, and learn why WordPress needs to “plug in” to the emerging agentic web!

Gutenberg 22.3, PHP Block Registration, and the Road to 7.0

A new year brings a fresh roadmap for WordPress, with the community now setting its sights on version 7.0. “It’s a brand new year, and that means that another exciting 12 months of WordPress development lies ahead,” writes Justin Tadlock in a recent blog entry. Highlights from the latest Gutenberg 22.3 release include a simultaneous control update for the Grid block and a dedicated Font Library screen under Appearance → Fonts.

On the technical side, PHP-only block registration is maturing, now supporting all metadata and allowing developers to build blocks entirely without JavaScript. New packages like @wordpress/image-cropper and updates to the @wordpress/abilities client are also paving the way for advanced media editing and a unified capabilities API in version 7.0. Meanwhile, WordPress Playground users can now enjoy a new management dashboard and a dedicated DevTools browser extension for deeper in-browser inspection.

For the full list of updates and new resources, read the original post here.

Bot Traffic Dominates 2026 Web Outlook

WP Engine recently released its 2025 Website Traffic Trends Report, signaling a major shift toward a “dual-audience” internet optimized for both humans and AI. Ramadass Prabhakar, CTO at WP Engine, warns that “the industry is underestimating the speed at which the internet is transitioning” into this new environment, where AI interaction is as critical as human consumption.

The report highlights a sobering reality: nearly 1 in 3 web requests globally now come from bots, and 76% of that traffic is unverified. These automated agents aren’t just background noise; they consume up to 70% of costly dynamic resources, such as server processing and performance bandwidth. This shift has transformed “Intelligent Traffic Management” from a niche optimization into a critical financial and performance imperative for 2026.

Security maturity is also becoming a primary driver of speed. Sites serving traffic exclusively over HTTPS were found to be 1 to 5 seconds faster in Largest Contentful Paint (LCP) than those using HTTP. Furthermore, the report identifies a “structural gap” in global performance, noting that roughly 50% of the top 10 million sites still do not use a CDN, despite the potential for a 20% improvement in LCP.

For web teams, the takeaway is clear: success in 2026 will depend on treating traffic management, security, and performance parity as a single, connected system. You can download the full report here.

WordPress 7.0 to Drop Support for PHP 7.2 and 7.3

The WordPress project is preparing for a significant technical shift with the upcoming release of WordPress 7.0, scheduled for April 2026. In an effort to modernize the platform’s infrastructure, support for PHP 7.2 and 7.3 will be officially discontinued. This move will raise the new minimum supported version of PHP to 7.4.0, while the minimum recommended version remains at 8.3.

The decision follows the project’s long-standing policy of retiring PHP versions once their combined usage falls below a 5% threshold. Recent data shows that usage for PHP 7.2 and 7.3 has now dropped below 4% across monitored installations. “The goal of increasing the minimum supported version of PHP is to ensure the long-term maintainability of WordPress,” writes John Blackbourn in a recent blog entry. “The benefits to increasing the minimum supported PHP version manifest over time across multiple areas, including the plugin and theme ecosystem, tooling and libraries for AI, the long-term perception of the WordPress project, developer relations, and eventually within the WordPress codebase itself.”

For those unable to upgrade their server environments immediately, sites running PHP 7.2 or 7.3 will remain on the WordPress 6.9 branch. While WordPress officially supports security updates for the current branch, fixes are typically backported to older versions as a courtesy. However, users are strongly encouraged to migrate to PHP 8.2 or higher to take advantage of superior performance and active security support.

You can read the full announcement and view the version usage breakdown here.

WP Engine Acquires Enterprise Agency Big Bite

WP Engine has announced the acquisition of Big Bite, a premier enterprise agency specialized in building advanced editorial platforms for some of the world’s largest media brands, including The Wall Street Journal and The Times.

As part of the acquisition, Big Bite’s agency operations will be wound down, with its engineering team transitioning into WP Engine’s organization. The goal is to develop intelligent, purpose-built software solutions that help global publishers and agency partners optimize content creation and digital workflows. Ramadass Prabhakar, CTO at WP Engine, noted that the acquisition advances the company’s commitment “to serve publishers with products that enable them to more efficiently create, organize, and share content.”

Jason Agnew, CTO and Co-Founder of Big Bite, expressed excitement about the merger, stating that by uniting their strengths in engineering, they can provide “even greater value to WP Engine’s agency partners looking to elevate publishing capabilities.” This acquisition marks a significant transition for Big Bite from a long-standing partner to an internal engine for WP Engine’s future enterprise publishing solutions.

You can read the full press release here.

The Ralph Wiggum Technique: Persistence through Iteration

The final weeks of 2025 saw the viral rise of a seemingly simple yet controversial coding methodology: the Ralph Wiggum Technique. While it might sound like a joke, this “dumb thing that works surprisingly well” has become a serious topic of discussion among agentic coders.

In its purest form, Ralph is a Bash loop. The technique involves putting an AI coding agent (like Claude) into a continuous while-loop. Instead of a human manually guiding every step, the loop repeatedly feeds the agent a requirements document until a specific “completion promise” is met. It’s an approach that prioritizes persistence over perfection, letting the AI iterate on failures until it finds a path to success.

The name, inspired by the Simpsons character Ralph Wiggum, reflects the philosophy of the project’s creator, Geoff Huntley. It embodies a certain “embrace of chaos” where an agent keeps trying, often in bizarre or unexpected ways, until the job is done.

According to a brief history by Dex, the technique isn’t just about running code in a loop. Instead, it’s an exercise in context engineering. Dex notes that Huntley used the technique to build “Cursed Lang,” a programming language with a stage-2 compiler written entirely by the Ralph loop.

One of the more fascinating phenomena Dex mentions is “overbaking”: if left running too long without tight constraints, the loop can develop emergent behaviors, such as suddenly adding post-quantum cryptography support to a simple project.

To understand the philosophy of “Iteration > Perfection,” check out the Ralph Wiggum AI Loop Technique documentation.

Ralph Wiggum at an old-fashioned Coleco computer. He has just finished spelling the word "CAT".

Why WordPress Needs to Plug Into the Agentic Web

For much of its history, WordPress has been the definitive open-source CMS for publishers seeking an intuitive editing experience and developers requiring a battle-tested technical stack. Traditionally, its role was straightforward: store content, expose it via templates or APIs, and render pages for users to browse.

In this article, Francis Agulto discusses how WordPress must evolve from a platform that is simply “readable” by humans to one that is actively “operable” by autonomous AI agents. He explores the critical role of the Model Context Protocol (MCP) in transforming WordPress from a passive content repository into an AI-native interface that advertises structured capabilities directly to agents.

What’s the most interesting news you’ve come across recently? Pop by Twitter and let us know.

The post Delicious Brain Bytes: WordPress 7.0 Roadmap, Gutenberg 22.3, and the Rise of the Agentic Web appeared first on Delicious Brains.

❌
❌