WordPress plugins

WordPress plugins: clear up the sprawl or build your own

Every WordPress plugin is third-party PHP code that runs with the same rights as the core. Thirty plugins are therefore not a question of tidiness, but thirty decisions of trust that were made once and never reviewed again. Sharpness Solutions GmbH in Oldenburg records the plugin inventory of existing WordPress installations, assesses every extension individually and says what stays, what gets replaced and what is better built in-house. The current version is WordPress 7.0.3 of 6 August 2026; 7.1 is released on 19 August 2026 and brings three changes that affect exactly this kind of custom-built extension. As of 17 August 2026. Telephone 0441 21 21 63 0, Mon–Fri 9:00–16:00.

Make an enquiry 0441 21 21 63 0 Mo – Fr, 9:00 – 16:00 Uhr

The point at which someone calls

Enquiries about plugins come in two forms. Either the list under Plugins → Installed Plugins has become so long that nobody can say for every entry what it does and whether it is still needed. Or exactly one function is missing, and the four plugins that supposedly provide it each do the wrong thing. On the scale of the problem: the Patchstack report “State of WordPress Security in 2026” counts 11,334 newly reported vulnerabilities in the WordPress ecosystem for the year 2025, 42 per cent more than the 7,966 of the previous year. 91 per cent of them were in plugins, 9 per cent in themes, and six in the core itself — all six rated low. 1,966 reports, 17 per cent, were rated high. And 46 per cent had no patch from the vendor at the time of publication. The risk does not lie in WordPress. It lies in what you have installed alongside it.

Nobody can name the purpose of every plugin

The list has grown over years: one extension for a campaign in 2019, two for the same caching problem, one that a former colleague tried out. All of them are activated. Nobody knows any more which function in the frontend depends on which plugin — and that is exactly why nothing is removed.

A plugin has quietly disappeared from the directory

If a plugin is closed on wordpress.org, WordPress continues to show it as current in the administration, because there is no update any more. Neither the plugin overview screen nor the site health check points out the closure. The absence of a message feels like a good state and is not one.

For that one function there is no usable plugin

What is needed is a price tier by customer group, an integration with the company's own ERP, or an approval workflow for editorial content. What the market offers covers part of it in each case and brings a lot with it that nobody needs. Three plugins plus glue code are then more expensive than one cleanly built extension of your own.

Something custom-built is attached to the editor, and 7.1 is due

A meta box, a custom block, an additional column in a list view: built three years ago, untouched since then, and it works. On 19 August 2026 WordPress 7.1 changes three things that affect exactly this kind of code. Whether your extension is affected cannot be seen from outside, only on a test system.

Why plugin sprawl is an operational risk

WordPress has no separation of rights between plugins. Every activated extension runs in the same PHP process as the core, with the same database rights, the same file system rights and access to every hook that WordPress offers. There is no sandbox, no capability boundary between two plugins and no declaration of which data an extension may touch. A plugin whose only job is to render contact forms can read orders, create user accounts and write files. This is not carelessness in the core, this is the extension model of WordPress, and it is one of the reasons for its wide use. The operational consequence is uncomfortable: the security level of an installation is not the average of all plugins, but the level of the weakest one. Thirty plugins are therefore thirty decisions of trust.

Two figures from the Patchstack report for 2025 belong in every decision document. First: 46 per cent of the reported vulnerabilities had no patch from the vendor at the time of public disclosure. Whoever defines security as “we update promptly” has no answer for almost half of the cases, because there is nothing to update. Second, the speed: the median time to the first exploitation attempt, weighted by observed attack intensity, is five hours. Among the heavily exploited vulnerabilities, 20 per cent were attacked within six hours, 45 per cent within 24 hours, 70 per cent within seven days. A monthly update window is not a protection concept against automated mass scans. The first measure is therefore not faster updating, but a shorter list.

Deactivating does not clear anything up. A deactivated plugin is still code in the directory wp-content/plugins, and whether one of its files can be reached and executed directly through the URL depends only on whether the author protected it against direct calls. The usual check for ABSPATH at the beginning of a file is a convention, not an obligation. Deactivated plugins also continue to be offered updates, which lengthens the list in the update window without anyone gaining from it. If an extension is not needed, it is deleted. Something usually stays behind in the process, though: only an author who supplies an uninstall routine through uninstall.php or register_uninstall_hook really clears away their options, tables and metadata. The rest leave data remnants that nobody can assign to anything later.

The third cost centre is overlap. Two caching plugins that overwrite each other's headers. An SEO plugin that sets meta information, and a theme that outputs the same information a second time. Three extensions that each take over part of the cookie banner. Such pairs cost nothing in licence fees and a lot in fault finding, because the behaviour depends on the load order and can change after every update. On top of that comes the ongoing effort: every plugin is an update candidate, a compatibility risk at every major release and an entry that somebody has to rule out when there is a fault. Twelve plugins can be switched through individually in one morning. Forty cannot.

The plugin inventory: what we record and what follows from it

The inventory is a table, not a feeling. Recorded per extension: name and slug, origin (the directory on wordpress.org, commercial vendor, built in-house, unknown), installed and available version, date of the last update by the author, order of magnitude of active installations, the value from the “Tested up to” field, open security reports, licence and term status for commercial plugins, and, in one sentence, the purpose: which function in the frontend or in the editorial work depends on this extension. Together with the question that most often remains unanswered: is it even being called any more? We fetch the basic data through WP-CLI, the rest through the directory, the change history of the vendor and a look into the code. Comparing the files against the version in the directory with wp plugin verify-checksums additionally shows whether someone has edited a third-party plugin.

When the maintenance state is assessed, the warning in the directory is a weak signal in both directions. The yellow box “This plugin hasn't been tested with the latest 3 major releases of WordPress” appears when the “Tested up to” field of the readme.txt does not name any of the last three major versions. It says nothing about faults, and it can be cleared by changing one line in the readme.txt without a single line of code being touched. Conversely, a missing warning does not mean that anyone is paying attention. Four other things are more reliable: the date and content of the last actual code change, how many support requests are unanswered, how the author reacted to the last reported vulnerability, and whether there is a named person or company behind it at all. For commercial plugins there is the additional question of whether the licence is still running — with most vendors an expired term means no updates, not even security-related ones.

The inventory turns into a decision per row, with four possible outcomes. Keep: the extension is maintained, is needed, has no duplicate. Replace: the function is needed, but the vendor is the weaker part of the construction, or two plugins do the same thing and one is enough. Remove: the function is no longer needed, or the core can do it itself by now — that happens more often than the list suggests. Build in-house: the function is business-critical, and there is no vendor you would want to entrust it to. Every row gets a reason and an effort estimate, so that the list stays usable without us. And we clear up one expectation beforehand: clearing up usually does not mean halving. Most plugins stay. The gain is that afterwards you can say why, for every single one.

When the vendor stops — and when the exit becomes expensive

An orphaned plugin does not announce itself. If an extension is closed on wordpress.org, the directory page only carries the note “This plugin has been closed as of [date] and is not available for download”, but nothing changes in your installation: there is no update, so WordPress shows the plugin as current. The reason for the closure is only disclosed after 60 days, and even then only as a rough category — wordpress.org does not give details. The category decides how urgent the case is. “Author Request” means: there is time for an orderly replacement. “Merged Into Core” means: the plugin can go, the function is now in WordPress itself. “Guideline Violation” or “Licensing/Trademark Violation” means: check what is actually running there. “Security Issue” means: act today. Because none of this appears in the administration, comparing the installed slugs against the directory belongs in the maintenance routine — otherwise you only notice it when somebody has found the vulnerability.

With an orphaned plugin there are four ways forward, and none of them is waiting. Replacement by a maintained alternative is the normal case, but it costs data migration if the old extension used its own tables or meta fields. Continuing the maintenance within your own area of responsibility is permitted for GPL-licensed plugins and is sometimes sensible, but it moves the responsibility entirely to you: a fork that nobody maintains is only a renamed orphaned plugin. Taking over the plugin in the directory is the orderly path if the author cooperates — the author can transfer the rights personally, and anyone who wants to hand a plugin over marks it with the tag adopt-me. If there is no answer, a procedure runs through plugins@wordpress.org: submit revised code, the plugin team writes to the author, and after 30 days without a reaction the handover can take place. With a plugin that is already closed, this path is considerably more difficult. That leaves new development of the function, if it is too important to depend on third-party code. Which path is the cheapest is decided by the scope of the function, not by habit.

The special case is page builders, because there it is not only the function that depends on the plugin, but the content. Elementor stores the page structure as JSON in the postmeta field _elementor_data; the field _elementor_css holds not content, but the CSS generated from it. The field post_content often stays empty or rudimentary. The global settings are also not stored as an option, but in a post of their own — the kit — which the option elementor_active_kit in wp_options only refers to. WPBakery stores its structure as shortcodes in post_content, which without the plugin leaves visible shortcode text instead of content. The block markup of the core editor, by contrast, sits in post_content as HTML with comments and stays readable markup even without anything else. The difference is not a matter of taste, but a calculation of costs for the day on which the builder is changed or discontinued: with the block editor you migrate markup, with a JSON builder you rebuild pages, page by page, with editorial acceptance.

This is why we assess a page builder that is in use instead of condemning it. If Elementor or WPBakery has worked for years, if the editorial team works with it and the vendor is active, there is no reason to tear the whole thing out in a maintenance project — the effort is out of all proportion. The exit makes sense on exactly two occasions: when the design is going to be replaced anyway and the content is restructured in a relaunch, or when the builder itself becomes a risk because it blocks a major update. What we deliver beforehand is the figure that is missing: how many pages are actually stored in the builder format, how many of them are plain text pages that can be transferred with reasonable effort, and which templates have to be rebuilt by hand.

Custom development: when it is right and when it is not

A plugin of your own is the right answer when the function concerns your business and not the internet in general. Four cases occur regularly. First, rules that apply only in your company: price tiers by customer group, approval processes, discount logic, configuration rules for products that need explanation. Second, interfaces to your systems — inventory management, ERP, PIM, CRM — because there the data model of the other side decides, and not the data model of a plugin vendor. Third, functions that have to be clean in terms of data protection and where nobody can explain where a ready-made plugin sends the data. Fourth, the case in which three extensions plus glue code are needed to achieve what one manageable plugin of your own does directly: then custom development is not the expensive option, but the cheap one — and the maintainable one.

For standard tasks the answer is no, even if that works against the order. Forms, backups, caching, image compression, metadata for search engines, redirects, two-factor authentication, cookie consent: there a maintained plugin has collected edge cases over years that you do not know and that we do not know straight away either — character set problems in attachments, mail servers that answer differently from the documentation, browsers that treat file fields in their own way. Anyone who asks us to develop a contact form does not get a cost estimate from us, but the names of two plugins. This works in the other direction as well: if a custom development does not pay off over the expected period of use, we say so before the quotation and not in the second project phase. A plugin that covers a function which is available ready-made is a maintenance burden without value in the long run.

What we build is built so that updates keep working. In concrete terms this means: no changes in the core, no changes in third-party plugin or theme directories, no patches that are overwritten by the next update. Extension happens through hooks and filters — add_action and add_filter — and through the registrations provided for blocks, REST routes, custom post types and meta fields. Everything of our own sits in a plugin of its own with its own prefix, so that function and option names do not collide with third-party code; theme adjustments belong in a child theme, not in the original. In addition there are the mandatory parts that cannot be seen from outside: capability checks and nonces for every writing action, prepared statements for everything that goes into the database, dependencies through the header “Requires Plugins” available since WordPress 6.5 instead of through a check in the code, a run with Plugin Check before acceptance, an uninstall routine, and the source code in your repository. A plugin that blocks a WordPress update is a construction fault and not a feature.

What WordPress 7.1 breaks in custom-built extensions

WordPress 7.1 is released on 19 August 2026, in parallel with WordCamp US in Phoenix. First a clarification, because it stands wrongly in many check lists: React 19 is not coming with 7.1. The upgrade was reverted after incompatibilities had appeared between the old and the new React version, and in the way plugins include React. 7.1 stays on React 18.3; Gutenberg offers an experimental flag for testing React 19. Anyone who builds their check list around React migrations is checking the wrong thing. The relevant breaking points are in three other places, and they affect precisely the code that nobody is watching: custom meta boxes, custom blocks, custom columns in list views, small administration pages from earlier projects.

The first and most important change: from 7.1 onwards the post editor is always in an iframe — independent of the theme type, independent of the block API version of the registered blocks and independent of that of the blocks in the content. Until then there was an exception: in 7.0 the block API version of the blocks actually used decided whether the editor was iframed, and before that the version of the registered blocks; block themes forced the iframe in any case. That is why many installations never saw the change. From 7.1 onwards there is no exception any more. What breaks is every piece of code that accesses the global document or window in the editor — that is, most of what reaches into the editor area with jQuery, MutationObserver instances on editor content, third-party scripts that are attached in the editor, and CSS that is meant to style content in the canvas through a global selector. The way forward is through an element in the canvas and its properties ownerDocument and defaultView instead of through the global objects; event listeners on the canvas are attached with useRefEffect and removed there as well. Styles have to be brought into the iframe through the registrations provided for it; CSS included globally no longer reaches the content.

The second change concerns the post list tables — and with them pages and custom post types as well. The leading th with scope="row" has moved from the checkbox column to the title column: the checkbox cell is now a td, and the title cell is a th that carries the title as its aria-label. For screen readers this is a gain, for extensions it is a breaking point in markup that had been essentially unchanged since 2010. Anyone who selects through the CSS class check-column in order to position a custom column, mark a row or attach an action menu now finds nothing; code that expects the title and the row actions inside a td breaks in the same way. Affected are custom columns in the post and page overview, list views of custom post types, JavaScript for bulk actions and all CSS that is calculated on the old column structure; anyone who has to serve both versions selects td and th together as a temporary measure. The third change is smaller and is noticed all the same: the property __next40pxDefaultSize has become ineffective, form elements render at a height of 40 pixels unconditionally. Anyone who laid out custom panels, sidebars or meta boxes for the earlier standard of 36 pixels — or worked with size="__unstable-large" — gets shifted layouts.

This is checked on a copy, not in the live system, and in this order: open the editor and read along in the browser console, use every custom block and every custom meta box once instead of only looking at it, click through every administration page with a list table, switch on WP_DEBUG with logging and read the log afterwards, and send custom plugins through Plugin Check. The reassuring part of this is the timing: WordPress has installed minor releases by itself since version 3.7, and plugins and themes on request since 5.5 — 7.0.2 of 17 July 2026 even arrived as a forced update, with critical security fixes. A major version step such as 7.1, by contrast, does not arrive on its own. You set the date. But that also means: whoever does not set it only postpones it — and then checks under time pressure against 7.2, which according to the schedule published on 12 August 2026 is due to be released on 9 December 2026.

Process

Send us your plugin list.

A screenshot of the page Plugins → Installed Plugins is enough to begin with; with an administrator account the assessment becomes more precise. You receive a written assessment for every extension — keep, replace, remove, build in-house — with a reason and an effort estimate, even if you place the order elsewhere afterwards. Sharpness Solutions GmbH, Edewechter Landstraße 161, 26131 Oldenburg. Telephone 0441 21 21 63 0, Mon–Fri 9:00–16:00, info@sharpness.de.

  1. 01

    Access and inventory

    We need an administrator account, SSH or SFTP access to the server, access to the database and, if available, the repository. The data is collected read-only: a list of all plugins with version, status and origin, the theme and any child theme, the WordPress and PHP version, and a file comparison against the versions in the directory. Nothing is changed in the live system during this step.

  2. 02

    Assessment per extension

    Every row is assessed individually: purpose and actual use, maintenance state of the vendor, open security reports, licence and term status, overlaps with other plugins, and cost in the request path. For commercial extensions we clarify who the licence is issued to — not rarely the previous agency.

  3. 03

    Decision document

    You receive the table with a recommendation for every row — keep, replace, remove, build in-house — each with a reason and an effort estimate, and separated into what can be done immediately without risk and what belongs on a test system. The document stays usable without us, even if you place the order elsewhere afterwards.

  4. 04

    Clearing up on a copy

    The work is done on a staging environment. Removal and replacement happen individually and in small steps, with a function test in between, because with simultaneous changes nobody can say afterwards which one caused the problem. We clear away data remnants as well, and we set up redirects if URLs are affected. The way back is documented before the first step.

  5. 05

    Development, if that is the decision

    First a specification in plain prose that your department can read, then the code: a plugin of its own with its own prefix, extension through hooks and filters, capability checks and nonces, dependencies through the header “Requires Plugins”, a run with Plugin Check, an uninstall routine, documentation. The source code sits in your repository, not in ours.

  6. 06

    Operation and the next major version step

    After that comes the question of who maintains the list in future: update windows, comparison of the installed slugs against the directory, checks of custom extensions before every major release — starting with 7.1. Response times are set by a service level tier: BASIC 24 hours, STANDARD 8 hours, ADVANCED 4 hours, PREMIUM 2 hours. Without an agreement we work in order of arrival within 48 hours during our business hours.

Projects on this system

A selection — not the full client list.

Frequently asked questions

How many WordPress plugins are too many?

There is no upper limit, and every number that is quoted is a guess. What matters is not the quantity, but whether you can say for every single plugin which function depends on it and who maintains it. An installation with forty maintained, named extensions is less of a problem than one with twelve of which four have had no author for years. The number becomes practically relevant in two places: in fault finding, because every plugin has to be ruled out individually, and at every major version step, because every plugin has to be checked individually.

How do I recognise that a plugin is no longer maintained?

The yellow notice in the directory saying that a plugin has not been tested with the last three major releases is only a first signal — it depends on the “Tested up to” field of the readme.txt and can be cleared by changing one line, without any code being touched. Four things are more reliable: the date and content of the last real code change, how many support requests are unanswered, how the author reacted to the last reported security vulnerability, and whether there is a named person or company behind it at all. For commercial plugins it also counts whether the licence is still running.

What do I do if a plugin has disappeared from the directory?

First clarify the reason: closures are only shown with a reason after 60 days, and even then only as a rough category. “Merged Into Core” means the plugin can go. “Author Request” allows an orderly replacement. “Security Issue” means act, today. Waiting for the disclosure is not a strategy, it is only the case in which no other information is available. The operational part is important: WordPress continues to show a closed plugin as current, because there is no update any more, and the site health check stays silent as well. Comparing the installed slugs against the directory therefore belongs in the maintenance.

Is it enough to deactivate a plugin instead of deleting it?

No. A deactivated plugin is still code on the server, and whether one of its files can be reached and executed directly through the URL depends only on whether the author protected it against direct calls — the widespread check for ABSPATH is a convention, not an obligation. The extension also continues to appear in the update window and lengthens the list without any value in return. If a function is not needed, the plugin is deleted, and the data remnants in options, meta fields and custom tables are cleared away with it.

When is a custom plugin worth it instead of a ready-made one?

When the function concerns your business and not the internet in general: rules that apply only in your company, interfaces to your inventory management or your ERP, data protection requirements where nobody can explain where a ready-made plugin sends data to. And in the case where three plugins plus glue code are needed for what one manageable custom development does directly. For standard tasks — forms, backups, caching, redirects, cookie consent — the answer is no, because there a maintained plugin has collected edge cases for years.

What does a custom WordPress plugin cost?

By effort, and the effort depends on four figures that are clarified before the quotation: the scope of the business logic, the number and type of interfaces involved, whether an operating interface in the administration is part of it, and how strict the requirements for multilingual support and accessibility are. A small extension that changes one rule in an existing process is a different matter from an integration with an ERP that has its own data model. There is no price list. If the custom development does not pay off over the expected period of use, we say so before the quotation.

Why do you not change anything directly in the core or in a third-party plugin?

Because both are overwritten by the next update, which leaves you with the choice of skipping the update or building the change in again. Both are expensive. Extension therefore happens only through the ways provided for it: hooks and filters, the registrations for blocks, REST routes, custom post types and meta fields, and a child theme for theme adjustments. What we build sits in a plugin of its own with its own prefix. A plugin that blocks a WordPress update is a construction fault and not a feature.

Does WordPress 7.1 break our custom-built extensions?

It is possible, and it affects custom developments in particular. Three points have to be checked. First, from 7.1 onwards the post editor is always in an iframe — independent of the theme type and independent of the block API version: code that accesses the global document or window in the editor breaks; the way forward is through ownerDocument and defaultView on an element in the canvas. Second, in the post list tables the leading th with scope="row" has moved from the checkbox column to the title column; extensions that select on the class check-column now find nothing. Third, __next40pxDefaultSize is ineffective, and form elements render at 40 pixels instead of the earlier 36.

Does WordPress 7.1 come with React 19?

No. The upgrade to React 19 was reverted after incompatibilities had appeared between the old and the new React version, and in the way plugins include React. WordPress 7.1 stays on React 18.3. Gutenberg offers an experimental flag that allows React 19 to be tested — that is interesting for preparing your own extensions, but not for the check list for the release. Anyone who plans their 7.1 check around React migrations is checking the wrong thing and leaves the three actual breaking points open.

What does it cost to move away from Elementor or WPBakery?

That depends on where the content is stored. Elementor stores the page structure as JSON in the postmeta field _elementor_data; _elementor_css contains the CSS generated from it, not content. post_content often stays empty. The global settings sit in a post of their own, the kit, which the option elementor_active_kit only refers to. WPBakery stores shortcodes in post_content, which remain as visible text without the plugin. The block markup of the core editor, by contrast, sits in post_content as HTML with comments and stays readable. In practice this means: with the block editor you migrate markup, with a JSON builder you rebuild pages. We count beforehand how many pages are really affected, instead of estimating.

Do we own the code of a custom-developed plugin?

Yes. The source code sits in your repository, the rights of use are set in the contract, and the documentation is part of the delivery. This is meant explicitly: you should be able to end the ongoing support without a function leaving with us. The second part fits with this — licences for commercial extensions are issued to your company, not to us, and when we take over an existing installation we first check whether that was the case so far. Dependency is a bad business model.

Can you take over plugins that another agency built?

Yes, that is the most frequent reason for a call. We look at the code beforehand and give a written assessment: how the extension was built, whether there are changes in the core or in third-party plugins, whether capability checks and nonces are present, how SQL and data storage are handled, and whether the extension is ready for 7.1. Only after that do we talk about ongoing support. In rare cases we decline, for example when central parts are only available as encrypted code — no responsibility can be taken for a state that cannot be inspected.

How quickly do you respond if a plugin takes the website down?

That depends on the agreed service level tier: BASIC 24 hours, STANDARD 8 hours, ADVANCED 4 hours, PREMIUM 2 hours response time, billed as a monthly flat fee per project. Response time means: when someone starts work on the case. Without an agreement, the basic commitment from the support page applies — work in order of arrival within 48 hours during our business hours, Mon–Fri 9:00–16:00. Cover outside these hours requires an explicitly agreed on-call service; without that agreement it does not exist.

Can we record the plugin inventory ourselves?

Yes, the technical part is quickly done with WP-CLI: wp plugin list returns the slug, status, version and available update, and wp plugin verify-checksums shows whether someone has edited a plugin from the directory. The work sits in the two columns that no machine fills in: which function in the frontend or in the editorial work depends on this extension, and is it still being used at all? If you have this list, send it along — then we start with the assessment and not with the data collection.

Enquiry

Do you know what each of your plugins does?

If the answer for more than two entries is “no idea”, that is the normal case and the reason to get in touch. Send us the list or an access account. We assess every extension individually and say what stays, what gets replaced and what is better built in-house — before any quotation.

  • An answer from someone who knows the system — no phone queue
  • An assessment before the quote, even when it advises against the project
  • Your details are sent to us by email, not into a third-party CRM

Spam protection: Cloudflare Turnstile — no cookies, no tracking.

Call Start a project