WordPress Plugin Development Troubleshooting: A Project Manager’s FAQ for Build Problems

WordPress Plugin Development Troubleshooting: A Project Manager’s FAQ for Build Problems

You signed off the scope, the developer started work, and now something is wrong. The plugin conflicts with another extension. The activation hook fails on a client staging site. A reviewer at the WordPress.org plugin directory flagged your submission. Or the team simply will not give you a straight answer about when the issue will be fixed. This FAQ is built for that moment, when a project manager needs to make a decision rather than read a tutorial.

The questions below are the ones I see asked, in some form, on almost every custom WordPress plugin engagement. They are organized in the rough order they appear during a typical build: scoping disputes, environment problems, code review failures, conflict diagnostics, security and compliance, release issues, and post-launch support. Use the decision table near the end to triage whether a problem is a developer fix, a vendor escalation, or a contract issue.

Notebook with handwritten triage notes and color-coded sticky markers covering scope, environments, and conflicts
Nataliya Vaitkevich / Pexels

Scoping disputes that stall the project before code is written

The developer says the requirement is out of scope. How do I tell if they are right?

Pull the signed scope document, the user stories, and any acceptance criteria. A feature is in scope when the user story or acceptance criteria explicitly describe the behavior, when the requested behavior is the only reasonable interpretation of the user story, or when the feature is required by a regulation or platform rule referenced in the contract. Anything else is a change request. Do not argue from the marketing brief or sales call notes; those are not specifications.

If the requested feature is genuinely ambiguous, the correct action is a written change order with a delta estimate, not an argument. A senior developer who refuses to write a change order is signaling they would rather absorb scope creep than document the trade-off, which is a different problem.

The plugin is bigger than expected. Should I split it into two plugins?

Split when the second plugin would serve a different user role, run in a different context (admin vs front end), or have a meaningfully different release cadence. Do not split for aesthetic reasons. A two-plugin architecture doubles your release surface, doubles your support tickets when one is updated and the other is not, and creates an activation dependency that confuses clients. If the only reason for splitting is that the main plugin “feels too large,” restructure the internal code into modules instead.

The client keeps adding features verbally. How do I protect the schedule?

Implement a written intake step for every new request. The simplest workable rule: nothing enters the sprint without a ticket, an estimate, and a written approval from the named decision-maker. Verbal commitments become ticket drafts that someone has to approve. If a senior stakeholder bypasses this, escalate the bypass itself rather than the feature, because the process problem will recur on every project until it is named.

Environment problems that look like code problems

The plugin works locally but fails on staging. Where do I start?

Eight times out of ten it is one of four things: a PHP version mismatch, a different WordPress version, a missing PHP extension, or a different MySQL/MariaDB version that handles a query subtly differently. Ask the developer to log the PHP version, WordPress version, active theme, and active plugin list on both environments, then diff them. Most of the cost of debugging environment-only failures comes from not collecting this baseline first.

A specific hook is firing twice on production but once on staging. Is the code wrong?

Probably not. Two common causes: an object cache (Redis, Memcached, or a hosting-level cache) is preserving the action subscriber across requests when it should not, or another active plugin is also subscribing to the same hook with a different priority. Have the developer add a debug log entry inside the hook that records the priority and the calling file. If the second entry traces to a different plugin, you have a conflict, not a bug.

The plugin breaks when the site is set to a non-English locale. Why?

The most common cause is string concatenation that assumes English word order, or a date-formatting call that uses PHP’s date() instead of WordPress’s date_i18n(). A second common cause is loading translation files before the init hook, which silently fails in current WordPress versions. A third is hard-coded UTF-8 byte lengths in string slicing functions that break on multibyte characters. Ask for a localization review as a discrete task, not as a bullet in a larger ticket.

Code review failures that block release

The plugin failed the WordPress.org review. What now?

Read the reviewer’s email in full and reply only after a senior developer has confirmed each point. The most common rejection reasons are: missing GPL-compatible license, calling external services without user consent (a privacy issue), shipping minified or obfuscated code without source, including premium libraries with incompatible licenses, missing input sanitization on form fields, and using file_get_contents on a remote URL instead of wp_remote_get. Each of these is a fix, not a debate. Disputes with the reviewer are almost always lost; the faster path is to fix and resubmit.

A security audit returned high-severity findings. Are they real?

Treat every high-severity finding as real until proven otherwise. The pattern I see is teams arguing about whether a SQL injection vector is exploitable in practice while the auditor moves to the next client. A faster process: classify each finding as either “fix now” or “fix in next minor release with a documented compensating control.” Anything involving unescaped database input, unsanitized file uploads, or capability checks missing on AJAX endpoints belongs in the first bucket regardless of perceived exploitability.

Two developers at a shared monitor reviewing log output during a conflict diagnostic session
Matheus Bertelli / Pexels

Conflict diagnostics: when the plugin is not actually the problem

A user reports our plugin “breaks the site.” How do I confirm?

Ask the user for three things before opening a ticket: the URL of the affected page, the exact error message or visible symptom, and the active plugin list. With that baseline, the developer can usually identify the conflict in under thirty minutes. If the user cannot provide an active plugin list, send them a screenshot of where to find it. Tickets that proceed without these three items consume disproportionate developer time and rarely produce a clean fix.

Two plugins both claim a conflict is the other plugin’s fault. Who is right?

Usually neither is fully right. The correct framing is: which plugin is doing something non-standard, and is that non-standard behavior necessary? A plugin that registers a custom autoloader, monkey-patches a WordPress core function with a filter, or modifies the global query in a way that affects every page on the site is taking on more responsibility for compatibility. That does not make the other plugin innocent, but it does mean the first one carries more obligation to test against the broader ecosystem.

The site is slow only when our plugin is active. Is it a plugin bug or a server issue?

Profile before you accuse. A Query Monitor session or a New Relic trace will tell you within a few minutes whether the slowness comes from your plugin’s database queries, external HTTP calls, file system operations, or PHP execution time. Common findings: an uncached query running on every page load, a remote API call without a timeout, or a hook firing on init that should be firing only on the relevant admin page. None of these are server problems even if they only appear under production traffic.

Security, privacy, and compliance questions

The client asks if the plugin is “GDPR compliant.” What is the honest answer?

A plugin is not GDPR compliant by itself; a site is. What you can answer honestly is whether the plugin processes personal data, what categories of data it processes, where that data is stored, whether any data is sent to third parties, and whether the plugin provides export and erasure hooks compatible with WordPress’s privacy tools. Document these as a privacy data sheet rather than a marketing claim. The site operator still has to write the privacy policy and obtain the right legal bases.

Should the plugin call home for license validation or telemetry?

If it does, the user has to be informed and given a way to opt out, and the call has to fail gracefully when the network is unavailable. The technical implementation is straightforward; the part that goes wrong is silent telemetry, license checks that block site rendering when the license server is down, and license calls that run on every page load instead of on a daily scheduled event. Move license checks to a daily transient and cache the response.

A user requests a complete data deletion. What does the plugin owe them?

If the plugin stores personal data tied to a user ID, it has to participate in WordPress’s personal data eraser interface so that a site administrator can fulfill the request from the standard tool. If the plugin stores data tied to email addresses or other identifiers outside the user table, the eraser has to handle those too. Test the eraser before launch with a real test account, because the failure mode (orphaned rows in custom tables) is easy to ship without noticing.

Decision table: who owns the fix?

Symptom First diagnostic step Likely owner Escalation trigger
Plugin breaks one specific theme Disable other plugins, switch to default theme, retest Plugin developer if reproducible with default theme; otherwise theme vendor Two days without root cause
Admin page white screen Enable WP_DEBUG and check error log Plugin developer Error log empty and issue not reproducible
Plugin update reverts user settings Inspect upgrade routine and database schema diff Plugin developer; treat as data-loss incident Any production data loss requires immediate escalation
Plugin slows down REST API Profile with Query Monitor on a REST request Plugin developer if hooks fire on REST requests unnecessarily P95 latency above agreed SLA
Plugin sends emails that go to spam Check SPF, DKIM, DMARC, and sending domain Site operator, not plugin developer Plugin uses hardcoded From address
Plugin admin UI broken in latest WordPress Check WordPress changelog for deprecated functions Plugin developer Plugin has not been tested against current major version
Plugin license activation fails Test license endpoint from server, check firewall License vendor; site operator if outbound HTTPS blocked License vendor unreachable for over an hour
Plugin conflicts with caching layer Identify which cached object holds stale data Joint: plugin developer and host’s cache configuration Cache invalidation cannot be reproduced manually
Decision table sketched on a whiteboard showing symptom, diagnostic step, and owner columns
Yan Krukau / Pexels

Release-day questions

The QA team wants to retest everything before release. The deadline is tomorrow. What do I cut?

Cut nothing from the test plan that maps to a known regression area, a customer-reported issue, or a feature touched in the last sprint. Cut tests that cover unchanged code paths only after confirming with the developer that those paths really were not touched (including indirectly through shared utility functions). The middle ground is risk-based testing: a smoke test of unchanged areas, full regression on changed areas, and an explicit go/no-go decision recorded in writing.

A late-breaking issue is reproducible only on production. Do we delay?

Three questions decide it. Does the issue affect the path of every user, or only an edge case? Does it have a workaround? Is there a known data-loss or security implication? If the issue affects everyone and there is no workaround, delay. If it affects a small fraction and has a workaround, document the workaround, ship, and patch in the next release. Production-only issues are almost always environment differences; investigating those should not block a release that is otherwise ready.

How do I version a hotfix without confusing the changelog?

Use semantic versioning honestly. A hotfix that does not change behavior beyond fixing the reported bug is a patch release: 1.4.2 to 1.4.3. A hotfix that adds a small feature is a minor release: 1.4.3 to 1.5.0. A hotfix that changes the database schema, removes a public filter, or alters the public API is a major release regardless of how small the change feels: 1.5.0 to 2.0.0. Most disputes about versioning are really disputes about whether the change is breaking; if it is, ship a major version and explain.

Post-launch support questions that look small but are not

A user is using the plugin in a way it was not designed for. Do we support it?

Document the supported use cases in writing. If a user’s situation falls outside them, the honest answer is that you do not support it but can quote a paid customization. A common failure is silently supporting unsupported use cases for a few months and then trying to pull back; users perceive the pullback as a downgrade. Far better to be clear from the start about what the plugin does and does not do, and to charge for adaptations.

The plugin’s lead developer is leaving. What happens to the project?

Trigger a handover plan before they leave, not after. The minimum is: documented architecture overview, a list of intentional design choices (with reasoning), an inventory of third-party services and credentials, and a recorded walkthrough of the codebase covering the parts that are not obvious from the source. If your contract did not require this, the next contract should. Plugins are long-lived; developers are not.

How long should we plan to support an old major version?

For commercial plugins, twelve months of security fixes for the previous major version is a reasonable baseline. For internal client plugins, the answer depends on the client’s WordPress version policy. Tie support to a clearly stated end-of-life date so that customers can plan upgrades. Open-ended support obligations accumulate silently and create a dependency tail that consumes time you should be spending on the current version.

Risk-control summary: what to monitor every week of an active build

The questions above describe what to do when a problem appears. The harder discipline is monitoring early, before a problem becomes a deadline issue. A practical weekly review covers a small set of indicators that tend to flag trouble while it is still cheap to address.

  • Scope changes accepted without written change orders this week. Target: zero. A single undocumented change usually means several are happening informally.
  • Open issues older than fourteen days. Aging issues become the late-stage backlog; if more than ten percent of issues are over two weeks old, the team is accumulating debt.
  • Test coverage on changed files. New code without tests creates regression risk that compounds; a falling trend deserves attention even if no test has yet failed.
  • Time spent on conflict triage versus feature work. A team spending more than a quarter of its time on conflicts is signaling either a flaky environment or a design problem that more triage will not fix.
  • Number of release blockers identified late in the cycle. If the same kinds of blockers appear repeatedly in the last week of a sprint, the testing schedule is wrong, not the team.
  • Documentation freshness. Compare the date of the last documentation update with the date of the last code change. A growing gap predicts onboarding pain and support cost.

Plugin projects do not usually fail in dramatic ways. They drift. A FAQ like this exists because the cost of drift is invisible until it suddenly is not, at which point the schedule, the budget, and the relationship have all moved beyond simple repair. Catching problems while they are still questions is the work.

Discussion

Join the Conversation

No comments yet

No comments yet

Start the discussion with a useful question, implementation note, or feedback that can help the next reader.

Comments are checked for spam. Helpful, specific replies make the article more useful for everyone.