Skip to content
  • FG-108
  • 11 min read
  • Last checked November 8, 2026

WordPress 6.9 Broke My Site: Known Issues and Fixes

Problems since WordPress 6.9? See the changes that broke sites (email sender, post navigation loops, classic theme styles), what 6.9.1 to 6.9.4 fixed, and how to roll back.

Run the health check

WordPress 6.9 “Gene” was released on 2 December 2025. It brought Notes for block-level feedback, the Command Palette across the whole dashboard, the Abilities API, new Accordion and Math blocks, and a batch of front-end performance work. For many sites it also brought surprises: contact forms that stopped sending mail, product pages that spun forever on a WooCommerce theme, blocks that looked slightly different on classic themes, and later, after the 6.9.2 security release, a blank front end on a small number of sites.

The 6.9 branch matters for longer than most. Sites still on PHP 7.2 or 7.3 cannot move to WordPress 7.0, so they stay on 6.9 and receive security fixes as backports. This guide covers the changes in 6.9 that commonly broke sites, according to the official 6.9 Field Guide and developer notes, the problems the 6.9.1 to 6.9.4 releases fixed, how to tell whether the update caused your issue, how to roll back with care, and where to report a bug.

What is happening

Major releases change behavior that plugins and themes lean on. When a plugin or theme assumed the old behavior, it breaks. When core shipped a bug, a point release fixes it. Here is the 6.9 branch timeline through early November 2026:

Release Date Contents
6.9 2 December 2025 Feature release
6.9.1 3 February 2026 Fixes for 49 bugs in core and the block editor, focused on bugs introduced in 6.9, including mail and classic theme issues
6.9.2 10 March 2026 Ten security fixes
6.9.3 10 March 2026 Fast follow fixing blank front ends on some themes after 6.9.2
6.9.4 11 March 2026 Completed security fixes that 6.9.2 had not fully applied
6.9.5 to 6.9.11 17 July to 28 October 2026 Security fixes backported from the 7.0 and 7.1 branches

Before you start

You need administrator access and either SSH or your host’s control panel. Back up files and the database first. If the dashboard is down, our critical error guide shows how to use recovery mode and the error log.

  • Server commands run in an SSH terminal from the site folder that holds wp-config.php, with wp or wp-cli depending on the host.
  • File edits happen in File Manager or over SFTP, or in a small must-use plugin file where noted.
  • Email header checks happen in your mail program, using its “show original” or “view source” option.

Step 1: Confirm the timing

wp core version --extra
ls -l --time-style=full-iso wp-includes/version.php

These run over SSH with no placeholders. The first shows your exact version and database revision. The second shows when core files were last updated, in the server’s time zone (on macOS or BSD use stat wp-includes/version.php). If you are on plain 6.9, on 6.9.2, or on 6.9.3, a fix for known problems already exists: update before anything else. Then compare the update time with the first matching entry in your PHP error log, mail log or form plugin’s log. A problem that started days before the update has another cause.

Step 2: Email stopped or changed after 6.9

What changed

The 6.9 developer note “More-reliable email in WordPress 6.9” describes three changes to wp_mail(). First, WordPress now sets the sender address (also called the Envelope-From or Return-Path, where bounces go) itself: it uses the address in the From header if one is present, and otherwise wordpress@ followed by your site’s domain. Before, many servers filled this in with something like the system user and server hostname. Second, PHPMailer’s encoding state is reset between messages. Third, multipart messages get the correct Content-Type. 6.9 also added support for inline embedded images in HTML email.

These are improvements, but a site that relied on the old behavior can see mail rejected, sent to spam, or bounced to a different address. The developer note says sites with custom email setups may need to use the wp_mail_from filter.

The known bug

Some sites saw mail fail outright with “Could not instantiate mail function” after 6.9. That was Trac ticket #64368, “Could not instantiate mail function errors sending mail in 6.9”, fixed in 6.9.1. If you see that error, update to the newest 6.9.x or later.

Check and fix the sender

Send yourself a test message from the server:

wp eval 'var_dump( wp_mail( "YOU@example.com", "Test from WordPress", "Sender test" ) );'

This runs over SSH. YOU@example.com is an inbox you can read. bool(true) means WordPress handed the message to the mail system; it does not prove delivery. bool(false) means sending failed immediately, so check the PHP error log or your SMTP plugin’s log. When the message arrives, open its original source and read the Return-Path line. If it shows a domain that your SPF record does not cover, receiving servers may reject or junk it.

The cleanest fix is to send through an authenticated SMTP or API mail service with a plugin, which sets the sender for you. If you need to set it in code, a must-use plugin is the right place:

<?php
add_filter( 'wp_mail_from', function () {
    return 'SENDER@example.com';
} );

This is a new file you create at wp-content/mu-plugins/mail-sender.php (create the mu-plugins folder if it does not exist). SENDER@example.com is an address on a domain your SPF and DKIM records authorize. WordPress loads every PHP file in that folder automatically. Check by sending the test again and reading the Return-Path and From lines. Our WordPress email guide covers SMTP setup and our sender requirements guide covers SPF, DKIM and DMARC alignment.

Step 3: Infinite loops in previous and next post links

6.9 fixed an old bug where next and previous post links failed when several posts shared the same publish date. The query behind get_adjacent_post() now compares the post ID as a tiebreaker, so the publish date appears twice in its WHERE clause. A developer note published on 10 December 2025 explains the side effect: plugins and themes that rewrite that WHERE clause with simple string replacement (through the get_next_post_where and get_previous_post_where filters) can end up returning the same post forever. That is Trac ticket #64390.

The note uses WooCommerce’s Storefront theme as the real-world example, because it navigates between products this way, and Storefront has since been fixed. Symptoms are single product or post pages that hang, time out with a 502 or 504, or exhaust PHP workers.

grep -rl "get_next_post_where\|get_previous_post_where" wp-content/themes wp-content/plugins

This runs over SSH with no placeholders. -r searches folders recursively and -l prints only the names of matching files. Any file listed belongs to a theme or plugin that modifies adjacent post queries. If it is Storefront or a Storefront child theme, update Storefront. For anything else, update the plugin or theme and ask its developer about 6.9 compatibility. No output means this is not your cause.

Step 4: A blank front end after 6.9.2

The official 6.9.3 announcement explains that after 6.9.2, a few users reported the front end of their site appearing blank. The cause was some themes loading template files through “stringable objects” instead of plain strings for file paths. The template_include filter only officially accepts a string, but the security team shipped 6.9.3 the same day so those sites worked again. A day later, 6.9.4 completed security fixes that had not been fully applied in 6.9.2.

If your front end went white around 10 March 2026 while wp-admin still worked, that is almost certainly this. Update to the newest release available to your site. If you develop themes, make sure anything you return from template_include is a string path.

Step 5: Classic theme and block styling changes

6.9’s performance work changed how block CSS reaches the page. The Field Guide lists on-demand block styles for classic themes, minified block theme styles, a higher limit for inline styles, and lower priority for non-critical scripts such as emoji detection and interactive blocks. It also lists a Heading block fix: the padding selector for headings with a background now requires both .wp-block-heading and .has-background.

On classic themes, this showed up as small visual shifts. 6.9.1 fixed several, including outlined buttons suddenly getting a gray background (Trac #64354), broken styling on the Add Plugins screen (Trac #64337), and missing default styles for the Accordion heading on classic themes. 6.9.1 also restored the HTML editing option in the Classic block and stopped the Accordion heading button from submitting forms.

If something still looks different on a classic theme after updating to the newest 6.9.x, inspect the element in your browser (right-click, Inspect) and compare which stylesheet each rule comes from. Theme CSS that relied on the old Heading padding selector, or on block styles that used to load on every page, may need a small update. 6.9 also removed support for enqueueing scripts and styles with Internet Explorer conditional comments, so any theme still doing that silently loses those files.

Step 6: Other 6.9 changes developers should know

  • Query cache keys. WP_Query cache keys are generated differently. Persistent object cache drop-ins should not be affected, but custom code that reads those keys directly should be checked.
  • Block API version 3. The block.json schema now only allows apiVersion 3 for new or updated blocks, and the browser console warns about blocks registered with versions 1 or 2. These warnings are a heads-up for later releases, not errors.
  • Admin menu search reads $_GET instead of the raw query string.
  • PHP support. 6.9 added beta support for PHP 8.5 and still runs on PHP 7.2 and later.
  • Export. A fatal error when wxr_cdata() received a non-string value (Trac #64347) could break Tools, Export with some plugins; 6.9.1 fixed it.

Step 7: Roll back to 6.8 safely, only if you must

Every 6.9.x release since 6.9.2 contains security fixes, and those fixes were backported to 6.8. If a critical plugin truly cannot run on 6.9, the safe target is the newest 6.8.x, which was 6.8.12 as of early November 2026. Check the WordPress releases archive for anything newer.

wp db export pre-rollback-YYYY-MM-DD.sql
wp core update --version=6.8.12 --force
wp core verify-checksums

These run over SSH. YYYY-MM-DD is today’s date for the backup file name; move it outside the web root afterward. --version selects the release and --force allows a downgrade. Good output is “Success: WordPress updated successfully.” followed by “Success: WordPress installation verifies against checksums.”

  • The database keeps any changes 6.9 made. Only the backup from right before the update restores the old state, and restoring it loses all newer orders, comments and posts.
  • Accordion, Math and other blocks introduced in 6.9, and any Notes left on blocks, have no equivalent in 6.8. Expect unsupported blocks in the editor.
  • Switch automatic updates to maintenance and security releases only under Dashboard, Updates, or set define( 'WP_AUTO_UPDATE_CORE', 'minor' ); in wp-config.php, or the site will update again.
  • If your problem is fixed in a 6.9 point release, rolling back is the wrong move. Update instead.

Step 8: Report a bug

Search the WordPress.org support forums and core Trac (core.trac.wordpress.org) for your exact error first; many 6.9 problems are already documented and fixed. If you can reproduce a new problem on a clean install with a default theme, file it on Trac with a WordPress.org account, including versions, numbered steps, expected and actual results, and log lines. Editor and block bugs go to the Gutenberg repository on GitHub. If you are unsure, ask in the “Fixing WordPress” forum first. Never post a security issue publicly: use the WordPress security team’s HackerOne program.

Advanced: prove an adjacent post filter is looping

A looping adjacent post filter rarely leaves a clear error. The page simply runs until PHP’s time limit, and the log shows a line such as PHP Fatal error: Maximum execution time of SECONDS seconds exceeded in /PATH/TO/SITE/wp-includes/FILE.php. The file named is just wherever PHP happened to be when time ran out, so it often points at core even though a theme caused it. You can prove the cause on a staging copy by switching the filters off temporarily.

Create the file wp-content/mu-plugins/test-adjacent.php on staging with this content:

<?php
add_action( 'template_redirect', function () {
    remove_all_filters( 'get_next_post_where' );
    remove_all_filters( 'get_previous_post_where' );
}, PHP_INT_MAX );

This is a temporary test file, not a fix, and it has no placeholders. It waits until just before the template renders (template_redirect at the latest possible priority, PHP_INT_MAX) and removes every callback attached to the two adjacent post WHERE filters. Now load the page that hung. If it loads instantly, one of those callbacks was looping, and the file list from Step 3 tells you whose. If it still hangs, the cause is elsewhere: check the PHP error log for other fatal errors and look at slow database queries instead, which our database performance guide covers. Delete the test file when you finish, because it changes how next and previous links behave for the whole site.

The same technique works for other suspected filter conflicts after any core update: remove the callbacks on one hook, on staging only, and see whether the symptom disappears. It is much faster than deactivating plugins one at a time when you already know which hook is involved.

When to contact your host

Contact your host if mail fails at the server level, if PHP is stuck below 7.4 and you need an upgrade path off 6.9, if updates fail partway, or if you cannot read the error log. Send:

  • UTC times of the update and of the first error.
  • The output of wp core version --extra and wp core verify-checksums.
  • Error log or mail log lines, and the full headers of a failed or junked test message.
  • What changed around the same time.

Our diagnostic tools help you check DNS, headers and status codes from outside your network, and the Emergency Room is the right place to start if the whole site is down.

Still stuck?

Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.

Get the free checklists

Keep reading

All field guides
FG-132 Updates

How to Update WordPress Plugins, Themes and Core Safely

A calm, repeatable update routine for WordPress: what auto-updates and core rollback protection really do, what order to update in, what to test afterward and how to roll one plugin back.

Read the guide
11 min read

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close