WordPress plugin to disable native features you do not need (RSS, comments, jQuery, posts/blog, XML-RPC, etc.).
true means the feature is disabled.
- Requires WordPress 6.0+ and PHP 8.0+
- License: GPL-2.0-or-later
- Packagist:
wp-performance/deaktiver - GitHub: WP-Performance/deaktiver
Composer (Bedrock / similar):
composer require wp-performance/deaktiverOr copy the plugin into wp-content/plugins/deaktiver (or web/app/plugins/deaktiver on Bedrock) and activate it.
Settings live under Settings → Deaktiver.
Two sources, in this order:
- Theme file
{theme}/config/deaktiver.php— if present, it wins. The admin form is then read-only (no database write). - Database option
deaktiver_config(admin UI), cached 24h in the transientdeaktiver_config.
A copy of the default keys lives in this repo at config/deaktiver.php (false = leave WordPress default).
Example theme config:
<?php
return [
'emoji' => true,
'embed' => true,
'feed' => true,
'xmlrpc' => true,
'jquery' => true,
'jquery-migrate' => true,
'version' => true,
'powered-by' => true,
'wlwmanifest' => true,
'rsd_link' => true,
'short_link' => true,
'rest_link' => true,
'comments' => true,
'posts' => true,
'rest_user' => true,
'login_url' => true,
'login_lang_selector' => true,
];Labels and descriptions for the admin UI come from config/options.php.
| Key | What it disables |
|---|---|
emoji |
Emoji scripts, styles, TinyMCE plugin, SVG CDN |
embed |
oEmbed discovery, rewrite rules, TinyMCE embed plugin |
feed |
RSS/RDF/Atom feeds, extra feed links, comment feeds |
xmlrpc |
XML-RPC, pingbacks, RSD; xmlrpc.php returns 403 |
jquery |
Front-end jQuery for guests (kept in admin, for logged-in users, and on wp-login.php) |
jquery-migrate |
jquery-migrate dependency on the front |
version |
generator meta / the_generator |
powered-by |
HTTP X-Powered-By (skipped if headers are already sent, e.g. page cache) |
wlwmanifest |
Windows Live Writer manifest link |
rsd_link |
Really Simple Discovery link |
short_link |
Shortlink in <head> and Link header |
rest_link |
REST discovery <link> and Link header |
comments |
Comments UI, widgets, admin screens, reply script |
posts |
Native blog (posts, categories, tags) — custom post types stay available |
rest_user |
/wp/v2/users for anonymous requests |
login_url |
Login logo URL/title point to the current site |
login_lang_selector |
Language dropdown on wp-login.php |
When posts is true:
- Admin: hide Posts menu, block native post / category / tag screens (403), remove Quick Draft and “New Post” in the admin bar. Custom post types on
post.php/post-new.phpare not blocked. - Front: 301 to home for single posts, category/tag archives, the posts index (
is_home), post-only author/date archives, post feeds, and post-only search. - Queries: exclude
postfrom front search and secondary queries (Query Loop, etc.). - REST: drop
/wp/v2/posts,/wp/v2/categories,/wp/v2/tagsand sub-routes. - Widgets: unregister Recent Posts, Categories, Archives, Calendar, Tag Cloud.
Layout:
deaktiver.php Bootstrap (plugin header, init)
config/options.php Admin labels
config/deaktiver.php Example theme config
src/Deaktive/ One class per option (`Deaktive{Key}`)
src/Options/ Settings page + AJAX save
admin-app/ Alpine + Vite settings UI
tests/ CLI unit tests (no WordPress boot)
A config key maps to a class: powered-by → Deaktiver\Deaktive\DeaktivePoweredBy (- / _ become camel case, prefix Deaktive).
- Add the key to
config/options.php(label + description) andconfig/deaktiver.php. - Add a class
src/Deaktive/Deaktive{Name}.phpextendingDeaktiveBasewithdisable(): void. - Hook only when needed; guard header changes with
headers_sent(). - Bump the plugin version in
deaktiver.phpand add a Changelog entry below.
composer test
# or
php tests/DeaktivePostsResolveTest.phpcd admin-app
npm install
npm run dev # Vite on https://localhost:9980 (HMR)
npm run build # writes admin-app/distThe public base path is derived from the plugin folder so Bedrock (/app/plugins/...) and classic (/wp-content/plugins/...) both work.
- Powered By: stop calling
header_remove('x-powered-by')after output has started (page cache / millicache). Remove the header immediately at plugin load, then again onsend_headers, and skip whenheaders_sent()is true to avoid PHP warnings.
- Posts / blog: extract admin post type resolution (
resolve_admin_post_type()) and add unit tests for CPT save vs native post block cases. Same allow/block behavior as 1.5.1.
- Posts / blog: fix CPT save on
post.phpwhenpostsis disabled — no longer 403 custom post types. Classic editor POSTs topost.phpwithout a query string; resolvepost_typefrom GET, then POST, thenget_post_type()of the edited ID. Native posts, categories and tags stay blocked.
- Posts / blog: new
postsoption to disable the native blog surface- Admin: hide Posts menu, block post/category/tag screens, remove Quick Draft and “New Post” admin bar item
- Front: 301 redirect to home for single posts, category/tag archives, post-only author/date archives, post feeds, and post-only search
- Queries: exclude
postfrom front search and secondary queries (Query Loop, etc.) - REST: remove
/wp/v2/posts,/wp/v2/categories,/wp/v2/tagsand related sub-routes - Widgets: unregister Recent Posts, Categories, Archives, Calendar, Tag Cloud
- Bootstrap: main plugin file renamed from
index.phptodeaktiver.php - Admin app: Vite upgraded to v8 (
rolldownOptions,import.meta.dirname), dynamic public base path for Bedrock (/app/plugins/...) and classic (/wp-content/plugins/...), Biome config updated for 2.x