I will soon lock down the b2evolution.net site. It will become read only and neither you nor me will be able to post new content to it.
Original post blogged on b2evolution.
The fourth feature release of Drupal 11 is another performance breakthrough. Using only a third of the database and cache lookups compared to Drupal 11.0 and 10.6 for the same requests. It also comes with 15-25% better compression of JS and CSS, much faster translation file handling, a new native command line interface, improved password hashing and a lot more.

With Drupal 11.3, we announced that it was the biggest performance improvement of the decade. Drupal 11.4 is arguably the biggest performance improvement of the decade again!
Drupal 11.4 reduces database queries by half compared to 11.3 across a wide range of requests due to optimizations in how entity fields are loaded.
Now, on a completely cold cache, Drupal 11.4 will execute just over 1/3rd of the database and cache lookups compared to Drupal 11.0 or 10.6, representing hundreds of milliseconds saved.
As well as entity loading, entity listing queries have also been significantly improved via reducing the number of table joins, leading to fewer slow queries. This should particularly benefit sites using JSON:API.
To reduce the cost of rendering menus and improve render cache hit rates, menu blocks now have a configuration option to not generate CSS classes for ancestor menu links.
We have made recipe-based site installation twice as fast. This significantly improves the UX of installing Drupal CMS and other site recipes. Installing individual recipes is also markedly faster.
Importing translations during the installer or during site operation is now much faster. On a test site with 66 projects and 38 languages, checking for translation updates was 87% faster on Drupal 11.4 compared to 11.3.
The APIs handling translation files and import have undergone an extensive modernization effort. All .inc files and several important APIs in locale.module have been deprecated and updated to OOP with special attention paid to performance and organization.
Drupal now supports Brotli compression for aggregated CSS and JavaScript files in addition to the existing gzip compression. Brotli typically provides 15-25% better compression ratios than gzip, resulting in faster page loads for browsers that support it. The feature relies on the PHP Brotli extension: ext-brotli.
The drupal/core-recommended package no longer pins minor versions for dependencies like Guzzle, Twig, and Symfony Polyfills. In the past, stricter version rules and Composer 2.9's blocking behaviour forced sites to wait for a new Drupal release to get important security fixes. Now, you can install these security fixes immediately. Since the updated dependencies at that time may not have been tested with Drupal core yet, site owners should ensure adequate quality assurance occurs before deploying to production.
A new extensible ./vendor/bin/dr command line interface was added. While Drupal already includes a CLI script with hardcoded commands, it is not extensible. This new interface was built by a team which included the maintainers of the Drush utility. Drush has been a mainstay for people using Drupal with the command line. Now a transitional period starts as Drush is gradually replaced with the core dr CLI over time. Learn how to make your existing Drush commands compatible.
The default installation, the Standard profile, is now leaner. It no longer includes the Article and Page content types, and commenting is disabled by default. Further core startup simplifications are planned for upcoming releases.
The Navigation module is now enabled in the standard administrative interface. The legacy Toolbar module remains available but is scheduled for removal in Drupal 12.
A new overview page has been added under the "Manage display" tab for content entity bundles. Previously, this tab led to the form editing the default view mode. Now, it lists all display modes for the bundle with their label and description and allows one to toggle the enabled/disabled status. The listing makes it easier to integrate tools such as Drupal Canvas.
Text formats using CKEditor can now be configured to include the FullScreen plugin. This plugin lets users expand the editor to the whole browser viewport, giving more space to comfortably edit content in a distraction-free environment.
The password hashing algorithm is now configurable. The new argon2id option provides much stronger hashing compared to the old bcrypt method. Drupal 12 will default to argon2id, but your site can already start to adopt it. If you update the setting, users' passwords will be rehashed on their next login.
You can now use attributes on your controllers to specify the routes the controller is used for. Any class in a module's Controller namespace (for example, Drupal\example\Controller) that have the Symfony\Component\Routing\Attribute\Route attribute will be picked up as route definitions. Even multiple routes can be defined on one class. This supplements the existing .routing.yml based declarations.
It is now possible to use the Drupal\Core\Entity\Attribute\Bundle attribute to define bundle classes, when in need of specific logic for an entity subtype. This previously required an entity_type_info or entity_type_info_alter implementation.
All .theme and .theme-settings.php files in core have moved to PHP classes. Support for .theme files is still planned to be retained in Drupal 12 to ease the transition, but will be removed in Drupal 13.
Most .module files have been converted too: 32 modules are fully converted to PHP classes, with 11 modules remaining (4 of which are deprecated for removal in Drupal 12).
A team of 26 key contributors worked on 57 issues since January 2026 to get here, making Drupal's code more consistent. Also thanks to the dozens of users that worked on the many decades old issues that this initiative built upon.
Drupal now integrates the Symfony Runtime component to separate bootstrapping logic from request handling. This provides a clear separation of concerns between preparing the environment (runtime) and handling a request, which will also later enable better integration with FrankenPHP.
A new trait for kernel tests, HttpKernelUiHelperTrait, allows kernel tests to make HTTP requests to the test site and make assertions against the returned content. This has the potential for many browser tests to be converted to kernel tests, which are much faster to run because unlike browser tests, they don't fully set up a test site by running the Drupal installer.
The Gin administrative theme has been added to Drupal core as the "Default Admin" experimental theme. The theme includes a new dark mode option.
While it is not yet actually the default admin theme, when it becomes stable it will replace Claro as the look of Drupal's backend. We encourage module maintainers to test their module's UIs and provide feedback!

Since Drupal 11.3 Andrei Mateescu was appointed as a provisional general core committer and is now a Content Moderation and the Workflows module maintainer too. Also Edward Wu was appointed as provisional release manager.
Various wonderful contributors also took our call for subsystem maintainership:
We also thank maintainers that stepped down in this period:
If you are looking to make the leap from Drupal user to Drupal contributor, or you want to share resources with your team as part of their professional development, there are many opportunities to deepen your Drupal skill set and give back to the community. Check out the Drupal contributor guide.
You would be more than welcome to join us at DrupalCon Rotterdam in September 2026 to attend sessions, network, and enjoy mentorship for your first contributions.
Drupal 12 will be released with the upcoming Drupal 11.5 at the beginning of December this year. Drupal 11.5 will be a Long Term Support release with version 11 support expected until the end of 2028.
[!CAUTION] v2.3.7 is a security release for sites on v2.3.6 or earlier.Upgrade from any 2.x at or below v2.3.6. If your site tracks the
masterbranch, you are already past v2.3.7, so installing it would be a downgrade. v2.4.x is planned to be the next forward step.[!IMPORTANT] Upgrade immediately. v2.3.7 closes two unauthenticated, network-reachable, Critical vulnerabilities. Neither requires authentication, user interaction, or any special privilege, and every public-facing site on v2.3.6 or earlier is exposed.
Remote code execution via
install.php(GHSA-c8h6-wpj3-4cr8, CVSS 9.8). Reachable on a default installation:install.phpstays live and exploitable after setup.Mitigation: Delete
install.php.- SQL injection throughout the e107 core (GHSA-5f75-c25x-59wx, CVSS 10.0). Request data is interpolated into SQL across ordinary, unauthenticated front-end request handling, including code an anonymous visitor triggers with a single page view (online-presence tracking writes the request URI into the database after a sanitizer that still permits the closing quote). It is not confined to any one plugin or feature, so no configuration change mitigates it. The only protection short of upgrading is to keep the site off the public Internet.
Treat this as an emergency upgrade.
install.php stayed reachable after setup and could be tricked into running an attacker's code, with no login. It now refuses to run once the site is installed, and the information the setup wizard carries between steps can no longer be used to smuggle in code. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/5d6d649e8c)e107_config.php first. Automated ("unattended") installs are only accepted on a site that is not already set up. Ref GHSA-c8h6-wpj3-4cr8. (https://github.com/e107inc/e107/commit/5d6d649e8c)alt_auth external-database login that the report originally came in on. There is nothing for you to configure and the site behaves exactly as before; installing this release is what protects you. Ref GHSA-5f75-c25x-59wx. (https://github.com/e107inc/e107/commit/120bd4bdbe)Host header a visitor's browser sends; it now rejects a malformed value and uses the server's own hostname instead. On a correctly configured site the existing host check already turns away mismatched hosts, so this is an extra safety net, and it also makes sure a non-standard port is kept in the links e107 generates. Ref #5734. (https://github.com/e107inc/e107/commit/a2f386b27f)media_cat_ui::createPage() called count() on an unset writeParms value when every category owner is restricted, throwing a TypeError under PHP 8. It now uses a null-safe check and keeps the same "category creation not available" behavior. Fixes #5741. (https://github.com/e107inc/e107/commit/d5e0d07814)row-reverse, so the visible order is unchanged and only the Enter behavior is fixed. (https://github.com/e107inc/e107/commit/2865e98f96)installStateTest builds the real guzzlehttp/psr7 POP chain and asserts the new JSON codec rejects it while round-tripping scalars; SqlInjectionFixesTest pins the core SQL-injection remediations; and acceptance coverage exercises the installer reinstall guard, paste-to-resume, and the unattended-install path end to end. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/892758085c)eShims::setcookie() options-array shim. Backported SetcookieTrait (the PHP 7.3+ options-array form with a pre-7.3 SameSite-into-path fallback) so the installer can set a hardened (HttpOnly, Secure, SameSite=Strict) resume cookie with one call across every supported runtime. Existing setcookie() callers are untouched. (https://github.com/e107inc/e107/commit/1063102678)install.php previously unserialize()d base64-encoded $_POST['previous_steps'] with no allowed_classes, at file scope on every request and again in the e_install constructor; the bundled guzzlehttp/psr7 PumpStream POP chain reached arbitrary callable execution once the decoded value flowed into site_path and was coerced to a string. Wizard state now travels as base64(JSON).hex(HMAC), verified in constant time on every request against a per-install CSPRNG signing token, and json_decode() only yields arrays and scalars, so object injection (CWE-502) is impossible by construction. e107_config.php is read as one of three positive states (fresh, install-pending, installed) instead of an emptiness check; the unattended ?create_tables path compares credentials with hash_equals() and refuses a database that already holds an e107 schema; and the finished config is written last, so a half-finished install never looks installed. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/5d6d649e8c)e_db prepared-statement API, tainted values are escaped inside their SQL quotes, numeric / LIMIT / OFFSET positions are (int) cast, and dynamic table/column identifiers are confined to a strict [A-Za-z0-9_] allowlist (escaping cannot protect identifiers). Import providers are fixed at the root in base_import_class::database(). Many sinks are reachable without a login: the online-presence tracker, for example, wrote e_REQUEST_URI into online_location after only FILTER_SANITIZE_URL, which keeps the single quote, so a crafted address reached the query directly. If you maintain a plugin that builds raw SQL from request input, mirror these. (https://github.com/e107inc/e107/commit/120bd4bdbe)e_db_pdo::escape() now escapes. The shared testEscape() expectation that codified the pass-through is updated, which makes the e_db_mysql override redundant. One caller (social_setup.php) used escape() on a value interpolated into an unquoted numeric context and is cast to int instead. (#5749, https://github.com/e107inc/e107/commit/b467b74f72)Host resolution helper (hardening). The request host is resolved through a shared resolveHttpHost() backported from master: it accepts the client Host only when it matches a host[:port] shape and otherwise falls back to SERVER_NAME, preserving the visited port. On a configured site the isAllowedHost() killswitch (added in v2.3.6) already rejects a mismatched Host before it reaches a URL, so this is defense-in-depth (covering an unset or misconfigured siteurl, and partial-bootstrap entry points that skip the killswitch) plus a regression lock: the accompanying e107HostValidationTest pins port preservation so a future sync from master cannot silently reintroduce the port-strip. (https://github.com/e107inc/e107/commit/a2f386b27f)CONTRIBUTING.md is now a policy document (backwards compatibility as the primary constraint, AI-assisted contributions welcome on the same quality bar, explicit rejection criteria for low-effort output), with matching PULL_REQUEST_TEMPLATE.md, issue forms, FUNDING.yml, and a new SECURITY.md. (https://github.com/e107inc/e107/commit/2b49a62ce8)e107Install.log was written into the docroot, where the shipped .htaccess has no rule for .log files, so its install diagnostics (DB host, table prefix, pref dumps on failure) were fetchable over HTTP. It now lives under the deny-by-default e107_system/. (https://github.com/e107inc/e107/commit/c1ef5bab81)e107_config.php could be served from the prior compile, hiding the freshly written provisioning lock. The installer now opcache_invalidate()s the file around each read and write. (https://github.com/e107inc/e107/commit/72b333107e)GitPreparer's rollback used git reset --hard && git clean -fdx, which destroyed uncommitted work on a crashed run. It now runs each suite inside a disposable git worktree with flock()-based orphan cleanup, never touching the main tree. (https://github.com/e107inc/e107/commit/aac93f1791)Both vulnerabilities were responsibly disclosed through GitHub Security Advisories. Our thanks to @baozongwi (GHSA-c8h6-wpj3-4cr8) and @Jimmi08 (GHSA-5f75-c25x-59wx) for the reports.
In modern SEO, small details often make a big difference. Meta tags such as meta_description, meta_keywords, and page_title still play an essential role in how your content is displayed and understood by search engines. They directly influence how your stories appear in results, and therefore how often users click them.
I’ve recently built a simple, lightweight utility that helps Geeklog site administrators automatically generate these fields using OpenAI’s API. It works with any Geeklog 2.x site and doesn’t require additional plugins or modifications.
The Geeklog AI SEO Updater connects directly to the Geeklog database and detects any stories missing a meta_description. For each one, it uses the gpt-4o-mini model to analyze the article’s title and introduction, then generates:
The script automatically detects the language of your site from $_CONF['language'] — it works in French, English, German, Spanish, Italian, and Japanese. You can test results safely in preview mode (?dry=1) or apply them in update mode with a defined article limit.
While modern search engines rely on full-page analysis, meta descriptions remain key to how your site looks in results. They act as your article’s “headline” on Google or Bing and have a strong effect on click-through rate.
Meta keywords, even though no longer used by Google for ranking, remain valuable inside Geeklog. They can be used for internal linking or automated features such as:
💡 For example, another script could automatically link stories that share two or more identical keywords, creating a stronger internal SEO structure.
The script only updates stories with empty meta descriptions and checks that you have the proper story.edit admin rights before execution.
# Preview mode (no database update)
https://yourdomain.com/admin/utils/update_meta.php?dry=1
# Update 10 stories
https://yourdomain.com/admin/utils/update_meta.php?limit=10
You can also schedule it as a weekly cron job to automatically optimize metadata for newly published stories.
This script lays the groundwork for more semantic features inside Geeklog. The generated keywords can later feed new modules such as:
By combining Geeklog’s simplicity with AI-assisted metadata, content becomes easier to navigate and better structured for both users and search engines.
The full documented code is available on the Geeklog Community Forum: 👉 https://www.geeklog.net/forum/index.php?forum=10
It supports PHP 5.6 +, Geeklog 2.x, and optionally integrates with the IndexNow plugin to notify Bing. Every line of the shared version is commented for easy understanding and adaptation.
With this AI-powered updater, Geeklog proves it can stay modern and efficient without losing its core simplicity. This approach helps keep older content relevant, visible, and better connected — with minimal effort and full control from the admin panel.
🧩 Author: Ben, Geeklog community contributor Discuss and download on the forum: https://www.geeklog.net/forum/index.php?forum=10
Posted October 28, 2025 | 7:41 pm