Last updated: July 2026
This page defines the technical, security, functional, packaging, documentation, licensing, compatibility and presentation requirements for WordPress plugins submitted to WPBay. It applies to new products, resubmissions and product updates.
These are minimum marketplace requirements, not optional suggestions. Meeting them does not guarantee approval: WPBay also evaluates whether the plugin provides genuine buyer value, is realistically usable outside the seller’s own development environment and is presented honestly. Approval is not a security certification and does not transfer responsibility from the seller. You remain responsible for the plugin’s code, dependencies, data handling, legal compliance, maintenance and support commitments.
This is the authoritative technical standard for WordPress plugins on WPBay. Older WPBay articles remain useful as background guidance, but this page takes precedence if an older example or recommendation conflicts with it.
How to read these requirements
The following terms are used deliberately:
- Must, required and must not describe approval requirements. A violation can block approval.
- Should describes an expected practice. A different implementation may be accepted when it is technically sound and clearly justified.
- May describes an optional practice.
- Blocker means an issue that must be corrected before approval.
- Recommendation means an improvement that normally does not block approval by itself.
WPBay reviews plugins against four broad standards:
- Technical quality: Is the code secure, maintainable, compatible and appropriately implemented for WordPress?
- Real-world readiness: Can an ordinary buyer install, configure, use, update and remove the plugin without hidden knowledge or avoidable failures?
- Buyer value and honest presentation: Does the product provide a genuine, working benefit and does the listing accurately describe what is delivered?
- Ownership and licensing: Does the seller have the right to sell every included component and are all applicable licenses respected?
Important clarifications to older WPBay guidance
Some examples in older marketplace articles reflect development practices from a much earlier browser and WordPress ecosystem. For current plugin reviews:
- Testing Internet Explorer 6, 7 or 8 is not required. Plugins must instead work in current supported versions of major browsers relevant to their users.
- Inline CSS is not automatically rejected. Static styling should be placed in properly enqueued stylesheets. Small, genuinely dynamic values may be added through WordPress APIs such as
wp_add_inline_style(), provided the output is safely generated and scoped. - A complete no-JavaScript copy of every interactive interface is not always required. Essential public actions should degrade sensibly where practical and every interface must remain accessible, keyboard operable and understandable. A complex admin application does not need to reproduce all functionality without JavaScript.
- A focused plugin is not rejected merely because it has few files or one main feature. It must, however, provide enough genuine value, reliability, documentation and polish to justify being sold as a product.
- Minified production assets are allowed. Minification must not be used to hide behavior and readable first-party source code must be included or otherwise made available for review.
Contents
- Submission and product readiness: review decisions, package, headers and versions, documentation and presentation, ownership and licensing and functional completeness
- Core engineering requirements: coding standards and architecture, security, data and migrations, performance, interface code, internationalization, accessibility and privacy
- Services, delivery and integrations: external services, dependencies, WPBay licensing and updates, platform compatibility, WooCommerce, high-risk categories and demo security
- Verification and submission: required testing, approval blockers, seller checklist, related WPBay guidance and official references
1. Review decisions and enforcement
WPBay may return one of the following decisions:
Approved
The plugin has no identified blocker after a proportionate code and product review. Approval does not mean that the plugin is guaranteed to be free from every defect.
Changes required
The plugin has one or more identifiable, repairable blockers. This is the normal result for security omissions, broken functionality, packaging defects, compatibility problems, misleading claims, incomplete integrations or substantial documentation gaps. The seller may correct the issues and resubmit.
Rejected
The plugin is malicious, deceptive, stolen, intentionally dangerous, deliberately obfuscated, fundamentally non-viable or built around behavior that WPBay cannot responsibly distribute. Repeated serious violations or attempts to conceal prohibited behavior may also affect the seller’s account.
Temporarily disabled after approval
WPBay may temporarily disable an approved product if a serious vulnerability, legal issue, broken update, malicious dependency or materially misleading claim is discovered later. Sellers are expected to respond promptly and provide a tested correction.
Automated tools support the review but do not decide it. Plugin Check, PHP_CodeSniffer, malware scanners, dependency audits and static-analysis results are evidence. Reviewers examine the surrounding code, verify likely false positives and assess the actual risk. Passing a scanner does not guarantee approval and a harmless style warning does not automatically justify rejection.
2. Required submission package
2.1 Installable ZIP
The submitted plugin archive must be directly installable through Plugins → Add Plugin → Upload Plugin on a standard WordPress installation.
The installable ZIP must:
- contain one clearly named top-level plugin directory;
- contain the main plugin PHP file directly inside that directory;
- contain every runtime file required for the advertised functionality;
- use a stable, unique, lowercase folder slug, normally with hyphens between words;
- use portable paths and consistent filename capitalization;
- extract without path traversal, invalid filenames, broken symlinks or operating-system-specific paths;
- avoid a second unnecessary wrapper directory;
- avoid requiring the buyer to locate another installable ZIP inside the downloaded ZIP;
- activate without manual file edits, Composer installation, npm installation, database imports or command-line build steps unless those requirements are intrinsic to a clearly identified developer product and are disclosed before purchase.
If WPBay provides a separate “all files and documentation” download, that package may contain documentation, design source files, examples or other buyer resources. The plugin ZIP inside it must still be immediately installable.
2.2 Stable plugin identity
The plugin folder, main plugin filename, text domain, WPBay license slug and update identity must remain stable across releases. Renaming an established plugin folder can cause WordPress to treat an update as a different plugin and can break licensing, activation records and automatic updates.
Do not change these identifiers after customers exist unless WPBay has approved a tested migration plan. A product rebrand may change the displayed name without changing the technical slug.
2.3 Files that must be included
Every plugin package must include:
- the complete production code;
readme.txtorREADME.md;license.txt,LICENSEor an equivalently clear license file;- a changelog, either inside the readme or in a separate clearly named file;
- any bundled third-party license notices required by those components;
- translation template files when the plugin is presented as translation-ready;
- configuration examples, templates or data files that are necessary for normal operation.
When first-party JavaScript, CSS or another runtime asset is compiled, bundled or minified, readable source and reproducible build instructions must be included or supplied to WPBay for review. A reviewer must be able to determine how the distributed asset was produced and compare it with the submitted source.
Online documentation may supplement the package but must not replace a basic included readme.
2.4 Files that must not be included
Remove unrelated or unsafe development artifacts before packaging, including:
.git,.svn, IDE metadata, operating-system files and temporary files;.envfiles, private keys, API credentials, access tokens, database passwords, signing secrets or live service credentials;- database dumps, production logs, customer data, support exports, email lists or analytics exports;
- backup files such as
.bak,.old,.orig, editor swap files and duplicate plugin copies; - test fixtures containing real personal information or credentials;
- unnecessary
node_modules, local Composer caches, build caches, coverage reports or large source archives; - unused demos, disabled experiments, placeholder modules, generated mock data or abandoned integrations;
- executable binaries or encoded payloads that are not essential, documented, licensed and reviewable;
- nested installable plugins unless the product is explicitly approved as a bundle and each component is separately licensed, maintained and documented.
Development source files may be included when they help buyers or are needed to satisfy open-source license obligations. They must not expose secrets or make the production package needlessly large.
3. Plugin headers, metadata and version consistency
The main plugin file must contain a valid WordPress plugin header. WPBay expects the following fields where applicable:
| Field | WPBay requirement |
|---|---|
Plugin Name | Required. Must match the product being sold and must not impersonate another product or brand. |
Description | Required. Must accurately summarize the active functionality. Do not advertise disabled, planned or non-working features. |
Version | Required. Must match the WPBay release, changelog, readme stable version and internal version constant. |
Requires at least | Required. Must be the oldest WordPress version actually supported and tested. |
Requires PHP | Required. Must match the syntax and dependencies used throughout the package. |
Author | Required. Must identify the seller or legitimate product author. |
Plugin URI | Recommended. Use the relevant WPBay product page or legitimate product website. |
Author URI | Recommended. Must be accurate and safe. |
License | Required. Must match the included license file. |
License URI | Required when a standard license has a canonical public URL. |
Text Domain | Required for translatable plugins. It should normally match the plugin slug. |
Domain Path | Required when translation files are stored outside the plugin root. |
Requires Plugins | Required when the plugin depends on eligible WordPress.org plugins. Premium or private dependencies must also be disclosed separately because this header cannot install them. |
Update URI | Use when necessary to prevent an unrelated WordPress.org plugin with the same slug from overwriting the product. It must not interfere with WPBay updates. |
WC requires at least | Required for WooCommerce extensions. |
WC tested up to | Required for WooCommerce extensions and must reflect real testing. |
All version declarations must agree. The following must not report different releases:
- the plugin header;
- readme stable tag;
- changelog;
- PHP or JavaScript version constants;
- database schema version where relevant;
- WPBay product version;
- downloadable package name, when the version is included in the filename;
- updater metadata.
Use a predictable versioning system, preferably semantic versioning. Breaking changes should not be shipped as silent patch releases. Database migrations, removed settings, renamed hooks, changed shortcodes and other buyer-impacting changes must be documented.
Do not claim compatibility with an unreleased WordPress, PHP, WooCommerce or dependency version unless the product is explicitly marked as a beta tested against a named prerelease. “Tested up to” means tested, not assumed.
4. Documentation and product presentation
4.1 Included documentation
The readme and documentation must enable a buyer who is familiar with WordPress, but not with the plugin’s source code, to install and use the product.
Document, as applicable:
- what the plugin does and who it is intended for;
- installation and activation;
- initial setup and a concise quick-start workflow;
- every significant setting and feature;
- required WordPress, PHP, WooCommerce, browser, server or extension versions;
- required and optional plugin dependencies;
- account, API key, webhook, cron, rewrite or permalink setup;
- third-party services, separate subscriptions, usage charges, quotas and geographical restrictions;
- where data is stored and what happens on deactivation or uninstall;
- user roles and capabilities needed to access features;
- scheduled tasks, background processing and timing limitations;
- import, export, backup and recovery behavior;
- public hooks, filters, shortcodes, blocks, REST endpoints, commands, template overrides and extension APIs when the plugin is intended to be extended by buyers;
- common errors and troubleshooting steps;
- known limitations and intentionally unsupported configurations;
- support status, support channel and the practical scope of support;
- update instructions and any special upgrade notes;
- a complete, readable changelog.
Instructions such as “configure normally,” “set the API,” or “edit the code as needed” are not sufficient when buyers need exact steps.
Documentation links must work without requiring an unrelated purchase, private account or inaccessible service. If the documentation is hosted online, the buyer must retain enough included information to install and recover the plugin if the external site is temporarily unavailable.
4.2 Product description
The WPBay listing must describe the package that is actually submitted. Every major claim may be tested.
The listing must clearly disclose:
- the main function and intended audience;
- meaningful feature limitations;
- all required dependencies;
- external services and paid accounts;
- recurring third-party costs or usage-based fees;
- free-versus-premium differences;
- license limits and activation limits;
- whether support is included;
- whether the plugin sends data off the buyer’s website;
- whether key functionality depends on the seller’s server;
- whether a feature is beta, experimental or available only in certain environments.
Do not describe unfinished screens, commented-out integrations, placeholders, mock data, roadmap features or code that exists in the package but is not reachable in normal use.
Claims such as “100% secure,” “fully GDPR compliant,” “guaranteed accessibility,” “unhackable,” “official,” or “works with every theme and plugin” require evidence that generally cannot be established by a normal plugin review. Use precise, limited language instead.
4.3 Screenshots and demos
At least one relevant product screenshot is required. Screenshots must show the current release, use readable content and accurately represent what a buyer receives. Do not use another product’s interface, fabricated results or features that are not included.
A live demo is optional unless WPBay requests one. When provided, it must be stable, safe, representative and reset appropriately. Demo security has additional requirements later in this document.
5. Ownership, licensing and selling rights
You must own the product or hold documented rights to sell and distribute it. This applies to the plugin code and every bundled component, including libraries, fonts, icons, images, audio, video, sample data, templates, AI-generated assets and documentation.
The product license may be GPL-compatible, MIT, proprietary or another license accepted by WPBay, but it must be legally valid for the submitted package and accurately disclosed before purchase. A proprietary product license does not override GPL, attribution, source-availability, redistribution or other obligations attached to incorporated components.
The package must:
- include a clear product license;
- retain copyright and attribution notices required by third-party licenses;
- include third-party license texts or a
THIRD-PARTY-NOTICESfile when required; - use dependencies under terms compatible with the way the product is distributed;
- comply with the WordPress license and the licenses of WordPress-derived components;
- identify forks and preserve notices required by the original project;
- avoid trademark misuse, false affiliation and product names designed to impersonate another vendor;
- avoid “nulled,” cracked, bypassed or unlawfully redistributed commercial code;
- avoid stock assets, fonts or demo media that the seller only has permission to use personally.
If requested, the seller must provide source, purchase records, contributor agreements, assignment agreements or other reasonable evidence of ownership and distribution rights.
AI assistance does not remove these obligations. The seller must verify that generated code and assets do not reproduce protected third-party material or introduce license-incompatible dependencies.
6. Functional completeness and real-world readiness
The plugin must work as described on a clean WordPress installation.
At minimum:
- installation, activation, deactivation, reactivation, update and uninstall flows must be tested;
- the plugin must not produce fatal errors, uncaught exceptions, common PHP warnings or notices, database errors, broken markup or JavaScript console errors during ordinary use;
- primary features must work from start to finish, not only render an interface;
- buttons, forms, filters, bulk actions, cron jobs, emails, exports, webhooks, update checks and background jobs must be connected to functioning handlers;
- success messages must not be shown when an operation failed;
- settings must persist correctly;
- required database structures must be created and migrated correctly;
- disabled or missing dependencies must result in a safe, useful admin notice rather than a fatal error;
- a plugin must not require the seller’s unpublished data, localhost paths, private credentials or manual database intervention;
- a fresh installation must not depend on tables, options, roles, files or scheduled events left behind by an earlier development version;
- no important workflow may be a placeholder, simulated result, hard-coded demonstration or “coming soon” control;
- errors from external services must be handled and explained without breaking the rest of the website;
- actions that can be retried must not accidentally duplicate orders, charges, emails, imports, refunds, records or scheduled events.
Complexity is not a requirement. A small plugin can be accepted when it solves a real problem exceptionally well. A code snippet placed behind a settings page, a thin wrapper around a free feature or a largely unfinished generated interface may be rejected when it does not provide credible paid value.
WPBay may also decline a submission that is a superficial rename, reskin or near-copy of an existing product and adds no meaningful buyer value. Differentiation may come from a materially better workflow, stronger implementation, a useful integration, professional documentation, reliable maintenance or another clear benefit; novelty for its own sake is not required.
7. WordPress coding standards and maintainable architecture
7.1 General standard
First-party code must substantially follow the current WordPress Coding Standards for PHP, JavaScript, CSS, HTML, accessibility, internationalization and inline documentation.
WPBay distinguishes style from risk. A few cosmetic spacing warnings normally do not block approval. Widespread standards violations, unreadable architecture, missing security controls, invalid callbacks, misuse of WordPress APIs or code that cannot reasonably be maintained can block approval.
7.2 Namespaces and prefixes
All globally accessible first-party identifiers must use a unique namespace or a sufficiently distinctive prefix. This includes:
- PHP functions, classes, interfaces, traits and constants;
- option, transient, cache, post meta, user meta, term meta and comment meta names;
- database tables;
- cron hooks;
- actions and filters;
- AJAX action names;
- REST namespaces;
- script and style handles;
- shortcode names;
- block names;
- JavaScript globals;
- CSS classes likely to appear outside a tightly scoped component.
Do not create first-party identifiers beginning with generic WordPress or WooCommerce prefixes such as wp_, wordpress_, woo_ or woocommerce_. A vendor or plugin prefix should normally be at least four characters and should be unique rather than a common English word.
7.3 File loading and direct access
Executable PHP files that are not intended as public endpoints should prevent direct execution, normally by checking ABSPATH.
Load files at appropriate WordPress hooks. Do not run expensive work merely because the plugin file was included. Admin-only code should not load or execute on every frontend request, but background and cron callbacks must still be registered during their execution context. Do not hide required cron, REST, AJAX, CLI or webhook handlers behind an incorrect is_admin() condition.
Callbacks registered with WordPress must be callable on every supported PHP version. Do not register a non-static method as a static callback, refer to a class that is not loaded or attach a method with the wrong accepted-argument count.
7.4 Use WordPress APIs
Use the relevant WordPress API instead of bypassing it without a documented technical reason. This includes:
- Settings, Options, Metadata, Transients, Cache, Filesystem, HTTP, Cron, Rewrite, Roles and Capabilities, REST, AJAX, Mail, Upload and Database APIs;
wp_enqueue_script()andwp_enqueue_style()for assets;- WordPress media and upload functions for uploads;
- WordPress HTTP functions instead of raw cURL;
- WordPress filesystem functions instead of assuming direct file permissions;
- WordPress date, timezone, locale, URL, path and escaping functions;
- WordPress post, term, user, comment and WooCommerce CRUD APIs instead of direct table manipulation where an API exists.
Do not redefine core functions, edit WordPress core files, require modifications to another plugin or write into another plugin’s directory.
7.5 Code quality
Code must be understandable by a competent developer. Use clear names, appropriately sized functions, coherent classes and comments where the reason for a non-obvious implementation matters.
The following can block approval when they obscure or endanger behavior:
- large duplicated code paths that have already diverged;
- contradictory schemas or multiple unfinished implementations of the same feature;
- dead production modules that reference missing tables, files, classes or columns;
- placeholder comments used instead of implementation;
- swallowed exceptions and ignored error results;
- pervasive suppression with
@; - global state without need;
- fragile string replacement of WordPress or WooCommerce interface text;
- hard-coded IDs, filesystem paths, domains, credentials, currencies, time zones or table prefixes;
- first-party code shipped only as minified, encoded, encrypted or machine-obfuscated output.
Third-party production libraries may be minified. Their identity, version, source and license must remain clear.
Treat documented public hooks, filters, shortcodes, blocks, REST routes, CLI commands, template interfaces, option names and stored data formats as buyer-facing APIs. Do not remove or rename them in a routine update without a compatibility layer, migration, deprecation notice or clearly documented breaking release.
7.6 AI-assisted code
AI-assisted and AI-generated code is allowed, but the seller must understand, review, test, maintain and support it.
Common AI-generation defects are reviewed in the same way as human-written defects, including:
- calls to nonexistent WordPress, WooCommerce or third-party APIs;
- database code that writes columns not present in the schema;
- interfaces connected to missing handlers;
- security checks added to some endpoints but omitted from equivalent endpoints;
- incompatible duplicated implementations;
- invented compatibility claims;
- placeholder logic, simulated results and comments that claim a step was completed when the code does not perform it;
- dependencies or copied code with unknown licensing.
Using AI as a development tool is acceptable. Publishing its output without technical verification is not.
8. Security requirements
Security is an approval requirement. Reviewers examine the actual attack surface rather than looking only for particular function names.
Treat all external data as untrusted, including:
$_GET,$_POST,$_REQUEST,$_COOKIE,$_FILESand request headers;- REST and AJAX parameters;
- webhook payloads;
- uploaded or imported files;
- remote API responses;
- database values that originated from users or third parties;
- post, term, comment, order and user metadata;
- URL parameters generated by another plugin;
- values submitted by administrators;
- filenames, archive entries, spreadsheet cells, XML, JSON and serialized content.
Administrators can make mistakes, accounts can be compromised, stored data can be modified by another vulnerable component and third-party services can return unexpected content.
8.1 Authentication, capabilities and object-level authorization
Every sensitive read or write action must verify that the current actor is authorized.
Use capabilities through current_user_can() or an equivalent WordPress mechanism. Do not authorize solely by role name. Use the narrowest sensible capability and perform object-level checks when a user may access only particular objects.
Examples of object-level authorization include verifying that:
- the current user can edit the specific post, order, user, file, form, ticket or record;
- a vendor owns the order or product being modified;
- a customer owns the order, download, message or license being requested;
- a webhook event belongs to the expected account and transaction;
- a purchase code is valid for the requested WPBay product;
- a multisite administrator is acting on an allowed site or network.
Possessing a numeric ID is never authorization. An endpoint that accepts order_id=123 must not assume that every logged-in user may read or modify order 123.
Code that creates roles, assigns capabilities, lets administrators map permissions or impersonates another user must prevent privilege escalation. A lower-privileged user must not be able to grant themselves or another account a capability they are not authorized to manage.
8.2 Nonces and CSRF protection
State-changing actions initiated from a browser must use an appropriate WordPress nonce:
check_admin_referer()for normal admin forms and URLs;check_ajax_referer()for authenticated AJAX requests;wp_verify_nonce()where a lower-level check is genuinely required;- the normal WordPress REST nonce/authentication model for cookie-authenticated REST requests.
Nonces protect against cross-site request forgery. They are not authentication, authorization, one-time replay protection, rate limiting or proof of ownership. A valid nonce must be combined with capability and object-level checks.
Do not perform destructive or state-changing operations merely because a GET parameter is present. Use a suitable request method, a specific nonce action, authorization, validation and an explicit result.
Public guest forms need controls appropriate to their risk, such as per-session tokens, rate limits, abuse controls, capacity limits and replay protection. WordPress generates the same default nonce identity for all guests, so a guest nonce alone is not sufficient for a high-risk public action.
8.3 Input validation and sanitization
Validate whenever the expected set or format is known. Sanitization is not a substitute for validation.
For every input:
- verify it exists before reading it;
- remove WordPress-added slashes with
wp_unslash()where appropriate; - cast it to the expected type;
- validate allowed values, ranges, formats, lengths and relationships;
- sanitize it with the function appropriate to the data;
- reject invalid values instead of silently converting a dangerous request into a different valid action.
Examples include:
- use
absint()for positive IDs, then verify the referenced object exists; - use
sanitize_key()and an explicit allowlist for action, status, sort, type and enum values; - use
sanitize_text_field()for single-line text andsanitize_textarea_field()for plain multiline text; - use
sanitize_email()followed byis_email()when an email address must be valid; - use
esc_url_raw()orsanitize_url()for stored URLs, then validate the permitted scheme and destination; - use
sanitize_hex_color()for colors; - use
wp_kses()with a deliberately limited allowlist when selected HTML is allowed; - recursively validate arrays, enforce maximum item counts and reject unexpected nesting;
- validate dates with a real date parser and store them in a documented time zone;
- validate MIME type, extension, size, dimensions and file content for uploads;
- set maximum lengths for messages, search strings, prompts, filenames and API payloads.
Do not pass an arbitrary user value into a function simply because it was processed by sanitize_text_field(). A sanitized value can still be unauthorized, out of range, logically invalid or dangerous in the destination context.
8.4 Escape output in its final context
Escape dynamic output as late as practical. Sanitizing when data is stored does not remove the need to escape it when displayed.
| Output context | Expected approach |
| Plain text inside HTML | esc_html() |
| HTML attribute | esc_attr() |
URL in href, src or similar output | esc_url() |
| Textarea content | esc_textarea() |
| Limited trusted HTML | wp_kses() with an explicit allowlist |
| Normal post-style HTML | wp_kses_post() when that level of HTML is genuinely intended |
| JavaScript data | wp_json_encode(), script data APIs or another context-correct encoding method |
| XML | esc_xml() or another context-correct XML encoding method |
| Integer or float | Explicit casting and, where displayed to users, locale-aware formatting |
Do not:
- use
sanitize_text_field()as output escaping; - use
esc_attr()for URLs whenesc_url()is required; - concatenate untrusted values into HTML or inline JavaScript;
- insert untrusted strings with
innerHTML, jQuery.html()or template literals without safe encoding; - assume a value is safe because it came from the database;
- suppress Plugin Check escaping errors without verifying every possible output path.
8.5 Admin forms, AJAX, REST and public endpoints
Every endpoint must have an explicit security model.
Authenticated AJAX actions must:
- verify a specific nonce;
- verify the required capability;
- verify access to the requested object;
- validate and sanitize every parameter;
- return structured success and error responses;
- avoid exposing personal, secret or administrative data unnecessarily.
wp_ajax_nopriv_* actions must be intentionally public. Public provisioning, import, AI generation, email, upload, search, registration and resource-intensive endpoints require strict server-side rate limits and abuse controls. Client-side throttling is not security.
REST routes must:
- be registered on
rest_api_init; - use a unique, versioned namespace;
- define an appropriate HTTP method;
- include a meaningful
permission_callback; - declare argument types, required fields, validation callbacks and sanitization callbacks where applicable;
- return
WP_REST_ResponseorWP_Errorobjects with suitable status codes; - avoid
__return_truefor sensitive data or actions.
A public read endpoint may use a public permission callback when the data is genuinely public. It still must avoid leaking drafts, private records, user data, secrets, internal IDs that create another attack path or unbounded datasets.
Do not add permissive cross-origin headers globally. Any CORS policy must use an explicit origin and method policy appropriate to the endpoint, must not reflect an arbitrary Origin and must not combine wildcard origins with credentials.
8.6 Database security and correctness
Use WordPress data APIs when they fit the job. When direct SQL is necessary:
- use
$wpdb->prepare()for every untrusted value; - use the correct placeholders for integers, floats and strings;
- build dynamic identifiers only from fixed, trusted values or strict allowlists;
- use
$wpdb->esc_like()before placing search terms inside aLIKEpattern; - use
$wpdb->prefixor$wpdb->base_prefixas appropriate; - never assume the database prefix is
wp_; - never concatenate request values into a query;
- check query results and handle failures;
- use appropriate indexes for real query patterns;
- paginate queries and enforce upper limits;
- avoid repeatedly querying the same record inside a list-table column or loop;
- avoid fragile
LIKEsearches over serialized or JSON arrays when a normalized relation is needed; - avoid
SELECT *when sensitive or large columns are unnecessary.
Financial, inventory, booking, license-seat, quota, refund, provisioning and similar operations must be concurrency-safe. A read-then-write check is not sufficient when two requests can pass it simultaneously. Use an atomic conditional update, unique constraint, transaction, lock, idempotency key or another appropriate database guarantee.
8.7 Files, uploads, archives, imports and exports
File handling receives additional scrutiny because mistakes can lead to remote code execution or data disclosure.
Uploads must:
- require the appropriate capability or deliberately secured public workflow;
- verify a nonce for authenticated browser actions;
- enforce file count and size limits;
- validate both extension and real file type;
- use WordPress upload functions where appropriate;
- generate safe filenames and avoid collisions;
- prevent PHP or other executable files from being uploaded into a web-accessible executable location;
- treat SVG, HTML, XML, archives and other active formats as high risk;
- store private files behind authorization rather than relying on an unguessable URL;
- never trust a browser-supplied MIME type;
- avoid returning server filesystem paths to the browser.
Archive extraction must prevent ../ traversal, absolute paths, symlink escapes, excessive uncompressed size, excessive file counts and overwrite of unrelated files. Validate every entry before extraction.
Remote URL imports must prevent server-side request forgery. Do not allow arbitrary schemes, localhost, private-network addresses, link-local addresses, cloud metadata endpoints or redirect chains into blocked destinations. Prefer safe WordPress HTTP functions and a strict allowlist when the feature permits it.
XML imports must use a parser configuration that prevents external-entity expansion and unintended network or local-file access. Reject malformed, deeply nested or excessively large documents before they exhaust server resources.
Imports must validate structure and limits before changing site data. An import failure must not leave a partially corrupted site without a recovery path.
Exports must enforce authorization and avoid leaking data from other users, vendors, sites or orders. CSV and spreadsheet exports containing user-controlled text must prevent formula injection from cells beginning with characters such as =, +, - or @.
8.8 Remote requests and external APIs
Use the WordPress HTTP API. Do not disable TLS certificate verification. Requests must use HTTPS unless a local-development feature has a narrowly documented exception.
Remote integrations must include:
- finite connection and request timeouts;
- handling for
WP_Error, non-success status codes, malformed bodies and unexpected content types; - sensible retries with limits and backoff where retrying is safe;
- caching when the same remote response is reused;
- quota and rate-limit handling;
- size limits before loading large bodies into memory;
- clear buyer-facing errors that do not expose tokens or internal details;
- a failure mode that does not break unrelated WordPress screens;
- validation of remote data before it reaches HTML, SQL, file operations or privileged actions.
Do not make unnecessary tracking calls, update calls, license calls or API requests on every frontend page load.
8.9 Webhooks and callbacks
Incoming webhooks must verify authenticity using the provider’s documented signature mechanism. Secure implementations normally require:
- signature verification over the exact raw body;
- a secret associated with the correct account;
- constant-time comparison where applicable;
- timestamp validation;
- replay protection or event-ID deduplication;
- verification that the event belongs to the expected site, order, customer, currency and account;
- idempotent processing;
- safe handling of out-of-order or repeated events;
- an appropriate HTTP response only after the event is accepted or safely queued.
A random-looking webhook URL is not sufficient authentication.
8.10 Secrets and credentials
API keys, passwords, signing secrets, private tokens, license secrets and payment credentials must never be:
- committed in the package;
- printed into public HTML;
- localized into frontend JavaScript;
- exposed in REST or AJAX responses;
- included in support diagnostics without redaction;
- written into publicly accessible logs;
- embedded in client-side source when they grant server privileges;
- sent over unencrypted connections.
Admin settings should redact saved secrets instead of repeatedly rendering the full value into the page. Do not overwrite an existing secret with a blank masked field during an unrelated settings save.
Use WordPress password APIs or modern PHP cryptography for passwords and sensitive tokens. Do not use MD5, SHA-1, predictable timestamps or rand() to generate security tokens. Encryption must use a reviewed authenticated-encryption design with a defensible key-management strategy; custom reversible “encryption” can be worse than transparent storage.
8.11 Dangerous execution and obfuscation
The following are investigation triggers and can be immediate blockers when unexplained or reachable with untrusted data:
eval(),assert()used as code execution, dynamicincludeorrequireand generated PHP;shell_exec(),exec(),system(),passthru(),proc_open()and similar process functions;- arbitrary SQL, shortcode, template, regex, command or PHP execution supplied by a user;
unserialize()on untrusted data;- decoding chains using
base64_decode(), compression, XOR, character maps or remote payloads; - downloading executable code outside the normal update process;
- ionCube or other encoding that prevents review;
- hidden admin users, backdoors, remote consoles, credential collection or stealth telemetry.
The mere presence of base64_encode() or a standard library’s minified code is not automatically malicious. The seller must be able to explain why any sensitive construct is necessary and how its input is constrained.
8.12 Redirects, email and generated content
Use wp_safe_redirect() for local redirects and allowlist any permitted external destination. Never redirect directly to an arbitrary request URL.
Email features must:
- validate recipients;
- prevent newline/header injection;
- distinguish transactional messages from marketing messages;
- enforce rate and volume limits;
- avoid duplicate sends during retries;
- report or log delivery failures safely;
- avoid placing secrets or unnecessary personal data in email;
- provide consent and unsubscribe behavior when messages are marketing rather than operational.
Generated HTML, PDFs, documents, QR codes, feeds and email templates must encode user-controlled content for their actual output format.
9. Data storage, schema migrations and cleanup
9.1 Options and metadata
Use uniquely prefixed keys. Store only what is necessary and use the narrowest suitable storage API.
Large arrays, logs, caches, generated content and queues must not be placed in autoloaded options. Avoid creating thousands of individual autoloaded options. Cache entries need expiration and invalidation behavior.
Do not store data in a core or another plugin’s option merely for convenience.
9.2 Custom database tables
Custom tables are acceptable when justified by query volume, relations, reporting or data shape.
They must:
- use the correct WordPress prefix;
- use the site charset and collation;
- have an explicit schema version;
- include indexes that match real filters, joins, uniqueness rules and scheduled queries;
- be created and upgraded by an idempotent migration;
- handle a failed or interrupted migration safely;
- avoid destructive changes without backup or a documented migration path;
- work on supported MySQL and MariaDB versions;
- use valid nullable/default values in strict database environments;
- not assume an earlier development table already exists.
Database migrations must run for existing buyers during an update, not only during first activation. A plugin must not display “updated successfully” when schema work failed.
9.3 Activation, deactivation and uninstall
Activation may create required tables, roles, capabilities, rewrite rules or initial options. It must not perform slow remote imports, bulk content generation or other work likely to time out.
Deactivation should stop or unschedule the plugin’s active processes, release temporary locks and flush plugin-specific runtime state where necessary. Deactivation must not normally erase customer data.
Uninstall behavior must be documented. Use uninstall.php or a registered uninstall hook for permanent cleanup. If the plugin offers “remove all data on uninstall,” the choice should be explicit and must remove only the plugin’s own data.
Never delete broad directories, shared uploads, core tables, another plugin’s data or content that cannot be confidently attributed to the plugin.
9.4 Time and date handling
Use WordPress timezone APIs and be consistent about whether stored values are UTC or site-local time. Do not compare a local database date to time() without conversion. Scheduled and displayed times must remain correct when the site timezone, daylight-saving offset or server timezone differs.
10. Performance and scalability
A plugin sold for use on public websites must behave reasonably with realistic content and traffic.
10.1 Conditional loading
Load scripts, styles, editors, libraries and admin code only where needed. Do not enqueue plugin assets on every frontend or admin page when the feature appears on one screen.
Avoid:
- heavy work at plugin file load;
- network requests on every page view;
- scanning all posts, orders, users, files or comments during a normal request;
- globally filtering every translated string when a narrower hook or screen check is available;
- loading large JavaScript frameworks for a small control;
- writing to the database on every page view without need.
10.2 Database performance
Avoid unbounded queries and N+1 patterns. A list table must not repeat the same assignment query for every custom column or make one query per related label, template or user when the data can be cached or fetched in a batch.
Queries should:
- be paginated;
- request only needed columns;
- use appropriate indexes;
- avoid leading-wildcard searches over large tables where possible;
- avoid loading full result sets merely to count them;
- use WordPress object caching or transients where appropriate;
- invalidate caches when relevant data changes;
- set defensible maximum values even when a
per_pageparameter is user supplied.
10.3 Background jobs and cron
Use WP-Cron, Action Scheduler or another justified queue rather than performing large jobs in a browser request.
Scheduled work must:
- register its callback in cron execution context;
- avoid scheduling the same recurring event repeatedly;
- clear or migrate events when the plugin is deactivated or the schedule changes;
- process bounded batches;
- use locks or atomic claiming to prevent concurrent duplicate processing;
- be idempotent where possible;
- retry only safe operations;
- record success only after the operation succeeds;
- expose enough status information for an administrator to diagnose a stalled queue;
- account for the fact that WP-Cron may run late on low-traffic sites.
Do not advertise exact-time delivery when the implementation relies only on normal WP-Cron traffic and no external scheduler.
10.4 External-service performance
Cache reusable API responses, respect provider quotas and do not block a public request for a slow nonessential call. Background processing should be used for expensive imports, AI generation, feed synchronization, image processing and bulk email.
11. JavaScript, CSS, HTML and interface behavior
11.1 Asset loading
Register and enqueue assets through WordPress. Declare dependencies accurately and use version strings that allow cache invalidation.
Use WordPress-bundled libraries where suitable instead of shipping conflicting duplicates. Third-party libraries must be maintained, licensed and free of known serious vulnerabilities.
Ordinary libraries should be bundled with the plugin rather than loaded from a public CDN at runtime. An official provider-hosted SDK may be accepted when the external service requires it, such as certain payment libraries, provided the dependency and privacy consequences are disclosed.
Do not include development-only hot-reload clients, localhost URLs, private source-map paths, console debugging or broken source references.
11.2 JavaScript security and quality
JavaScript must not:
- trust hidden fields, disabled inputs, prices, product IDs, permissions or totals as authoritative;
- expose server secrets;
- create DOM-based XSS through unsafe HTML insertion;
- use
eval(), dynamically generated functions or unsafe executable strings; - silently ignore failed AJAX or REST responses;
- depend on timing hacks when a documented event or state transition exists;
- generate duplicate requests because events are bound repeatedly;
- throw console errors during normal use.
Server-side authorization and validation are required even when the JavaScript interface prevents an invalid action.
First-party JavaScript should be readable and structured. Complex blocks and applications should use WordPress packages and build tooling appropriately, declare script dependencies and include translation support.
11.3 CSS
Static CSS should be in properly enqueued stylesheets. Dynamic inline styles are acceptable when they are genuinely dynamic, safely generated and added through the appropriate WordPress API.
CSS must:
- be scoped so it does not unexpectedly change unrelated admin or frontend screens;
- avoid generic selectors that override the active theme or WordPress globally;
- avoid excessive
!importantrules used to fight other products; - remain usable at common desktop and mobile widths;
- respect left-to-right and right-to-left layouts where relevant;
- preserve visible focus and accessible contrast;
- avoid loading large unused frameworks;
- use valid, maintainable syntax.
11.4 HTML and semantics
Use valid, semantic HTML. Controls must use the correct element: links navigate, buttons perform actions, labels identify fields, headings form a meaningful hierarchy and tables are used for tabular data.
Do not place block-level structures inside invalid inline containers, create duplicate IDs or rely on placeholder text as the only label.
11.5 Admin user experience
Admin interfaces should feel like part of WordPress and must not interfere with unrelated screens.
The plugin must:
- show clear validation errors near the relevant action;
- preserve entered values after a recoverable error where safe;
- avoid success notices when nothing was saved;
- confirm destructive actions;
- prevent duplicate submissions;
- use capabilities consistently for menus and handlers;
- avoid persistent dashboard-wide advertisements, fake system notices and notices that cannot be dismissed;
- avoid redirecting users to an onboarding or marketing page after every activation or update;
- avoid adding a top-level menu when a relevant existing menu is more appropriate;
- avoid hiding WordPress warnings or another plugin’s notices;
- avoid creating public pages, posts, users, orders, products or sample data without an explicit setup action;
- avoid silently changing site-wide settings such as the homepage, registration policy, permalink structure, mail sender, user roles or default content behavior.
12. Internationalization and localization
All user-facing first-party strings should be translatable unless the string is user content, a technical identifier or supplied by an external service.
Requirements include:
- use the plugin’s consistent text domain;
- keep literal source strings inside translation functions;
- use translator comments for placeholders whose meaning is not obvious;
- use numbered placeholders when translators may need to reorder values;
- use
_n()or equivalent plural handling; - escape translated output for its context;
- load JavaScript translations through the appropriate WordPress mechanism;
- do not concatenate fragments that translators cannot reorder naturally;
- use WordPress date, number and currency formatting;
- avoid hard-coded English labels, date formats, decimal separators and currency assumptions;
- support RTL presentation for relevant interfaces.
Bundled translation files must correspond to the current source. A stale .pot containing only a small fraction of the plugin’s strings is not evidence that the plugin is translation-ready.
13. Accessibility
New and updated interfaces are expected to follow the WordPress accessibility standard and target WCAG 2.2 Level AA where applicable.
Reviewers may check:
- full keyboard access;
- visible focus;
- logical focus order;
- correct labels, descriptions and error associations;
- semantic headings, lists, tables, buttons and links;
- sufficient color contrast;
- information not conveyed by color alone;
- alternative text for meaningful images;
- screen-reader announcements for dynamic changes;
- accessible modals, menus, tabs, accordions and dialogs;
- no keyboard traps;
- adequate target sizes and responsive reflow;
- respect for reduced-motion preferences;
- captions or transcripts for essential media;
- accessible names for icon-only controls.
Use native HTML controls before ARIA. ARIA must accurately describe actual behavior and must not be added merely to silence a checker.
14. Privacy, telemetry and legal claims
14.1 Privacy by design
Collect and retain only data necessary for the feature. Use privacy-preserving defaults. Give site owners meaningful control over optional collection and transmission.
If the plugin collects, stores, processes or transmits personal data, document:
- the exact data;
- the purpose;
- where it is stored;
- every recipient or external service;
- the retention period or deletion condition;
- who can access it;
- how it is exported and erased;
- any lawful reason certain records cannot immediately be erased.
Use WordPress privacy-policy suggestion hooks where appropriate. Integrate with personal-data export and erasure tools when the plugin stores personal information not already handled by WordPress or a declared dependency.
14.2 Telemetry and tracking
Telemetry, usage analytics, tracking pixels, remote images, marketing beacons and nonessential error reporting must be opt-in. Consent must be informed, specific and reversible.
Do not:
- enable telemetry silently;
- treat plugin activation as analytics consent;
- send the site URL, administrator email, installed-plugin list, content, license data or server details without a documented need and appropriate permission;
- load a third-party resource solely to count installations;
- hide telemetry inside a license or update request;
- continue collection after opt-out.
Essential license and update requests are not automatically “telemetry,” but they must transmit only necessary data and must be disclosed.
14.3 Logs and diagnostics
Logs must not be publicly accessible. Limit and rotate them. Redact passwords, tokens, payment data, private messages and unnecessary personal information.
Diagnostic exports must show the administrator what will be included before transmission. Do not silently send a full database, environment file, access token or customer record to support.
14.4 Compliance claims
Do not claim that installing the plugin automatically makes a website compliant with GDPR, CCPA, accessibility law, tax law, accounting law, PCI DSS, medical regulation or another legal regime.
A narrower claim may be acceptable when the feature is precisely described. For example, “includes tools to record consent events” is different from “makes your site GDPR compliant.”
14.5 Advertising, attribution and affiliate behavior
A plugin must not inject hidden links, SEO spam, advertisements, tracking pixels or promotional content into the public site. It must not require a visible “powered by” credit unless that condition is prominent before purchase and allowed by the product license.
Admin upsells must be relevant, truthful, proportionate and confined to the plugin’s own screens or an appropriate dismissible notice. Do not imitate core security warnings, manufacture urgency, obscure normal controls or degrade an advertised paid feature to force another purchase.
Affiliate links and referral relationships must be disclosed. Do not replace a buyer’s affiliate ID, add a referral parameter without consent, intercept outbound links unrelated to the feature or earn commission from a required service without making that commercial relationship clear.
15. External services and required accounts
External services are allowed when they are intrinsic to the advertised feature and buyers receive clear information before purchase.
The product page and documentation must identify:
- the service provider;
- why the service is needed;
- what data is transmitted;
- whether an account is required;
- free and paid limits;
- separate charges;
- supported countries or currencies;
- relevant terms and privacy policy;
- what stops working when the service is unavailable;
- whether the buyer can change provider.
The plugin must not become unusable merely because a nonessential marketing, analytics, license or update server is unavailable.
Features dependent on a seller-operated service require a credible operating model. WPBay may reject a product whose core value depends on an undocumented, unmaintained, insecure or obviously temporary endpoint.
16. Dependencies and third-party libraries
Every dependency must be deliberate, obtainable, maintained, compatible and disclosed.
The plugin must:
- declare WordPress.org dependencies using
Requires Pluginswhere supported; - safely detect dependencies on older supported WordPress versions;
- document premium, private, server, PHP-extension or account dependencies that the header cannot install;
- fail safely when a dependency is missing, inactive or below the required version;
- avoid referencing a dependency constant or class before checking it exists;
- avoid fatal errors when a dependency is deactivated before the plugin;
- not bundle a modified copy of another active plugin as a hidden dependency;
- avoid conflicting duplicate versions of common PHP or JavaScript libraries;
- scope or isolate Composer dependencies where collision risk is material;
- include production dependencies only;
- keep libraries updated and address known serious vulnerabilities;
- retain third-party license and attribution requirements.
Run dependency audits before submission. A package with a known exploitable library may be blocked even if the seller did not write that library.
17. WPBay licensing and updates
Licensing is optional unless required by the product’s business model. If the plugin implements license activation or automatic updates, the WPBay version must support WPBay buyers.
17.1 Licensing
A WPBay plugin must not:
- require an Envato, CodeCanyon, another marketplace or unrelated store purchase code;
- activate only against a product ID owned by another marketplace;
- require the buyer to repurchase the plugin elsewhere;
- contain a bypassed, cracked or nonfunctional licensing implementation;
- disable advertised local functionality merely because the seller’s licensing server has a temporary outage, unless that limitation is inherent and clearly disclosed;
- expose API secrets or allow one customer’s code to control another customer’s activation.
Use the WPBay license API or SDK when license verification is needed. License checks must use HTTPS, validate responses, handle timeouts, respect activation limits and provide a practical deactivate/reset path.
The technical license slug must remain stable across updates and rebrands.
Document what happens when a license expires, is deactivated, reaches its activation limit or cannot contact the license server. A license failure must never delete or corrupt buyer data, block access to recovery or deactivation controls or turn a temporary network failure into a permanent lockout.
17.2 Updates
Update code must:
- request updates only for the correct plugin;
- use a stable plugin basename and slug;
- compare versions correctly;
- use HTTPS;
- validate remote responses;
- download only from trusted, expected sources;
- avoid accepting an arbitrary package URL from a user or unrelated API response;
- preserve settings and customer data;
- run tested, versioned migrations;
- avoid overwriting another plugin;
- display release and compatibility information accurately;
- continue to let WordPress handle the installation process.
An update must not download and execute PHP as a substitute for the normal WordPress plugin update mechanism.
Do not silently self-modify production PHP or JavaScript, write executable modules into the plugin directory or operate a second hidden updater outside the normal, disclosed update flow.
18. WordPress and server compatibility
18.1 Declared versions
The minimum WordPress and PHP versions must reflect the entire package, including Composer dependencies and optional code paths. Do not declare PHP 7.4 while shipping syntax or a library that requires PHP 8.1.
Test at minimum:
- the oldest declared WordPress version, when reasonably available;
- the current stable WordPress release;
- the oldest declared PHP version;
- at least one current supported PHP release;
- current supported versions of required dependencies.
The plugin must not depend on deprecated behavior that has already been removed from a declared compatible version.
18.2 Common hosting environments
Unless clearly sold for a specialized server environment, the plugin should work on normal WordPress hosting without:
- root access;
- a persistent Node.js or Python process;
- shell commands;
- a particular control panel;
- Apache-only rewrite rules;
- writable plugin files after installation;
- unusually high memory or execution limits;
- disabled TLS verification;
- manual cron configuration for basic operation.
Special server requirements are acceptable only when they are essential, prominent in the listing and correctly tested.
18.3 Multisite
Do not claim multisite compatibility unless tested.
When multisite is supported:
- network activation and per-site activation must behave as documented;
- tables and options must use the correct site or network scope;
- new sites created after network activation must be initialized;
- data access must not cross site boundaries without authorization;
- uninstall must not accidentally remove data belonging to other sites;
- super-admin-only actions must use the correct capabilities.
If multisite is intentionally unsupported, fail safely and disclose it before purchase.
18.4 Compatibility with other products
Plugins must coexist with WordPress core, a default theme and common extensions relevant to their purpose. Avoid generic globals, broad CSS, unscoped JavaScript, global output buffering, replacement of core screens and filters that alter unrelated content.
You are not required to guarantee compatibility with every plugin or theme. Known material conflicts and exclusive integrations must be disclosed.
19. WooCommerce extension requirements
Plugins that declare or advertise WooCommerce integration receive additional review.
19.1 Dependency and metadata
The plugin must:
- declare WooCommerce as a dependency;
- provide accurate
WC requires at leastandWC tested up toheaders; - avoid referencing WooCommerce classes or constants before confirming WooCommerce is active;
- deactivate or remain safely dormant when WooCommerce is unavailable;
- provide a useful notice to an authorized administrator;
- avoid a fatal error when WooCommerce is deactivated first.
19.2 HPOS and order APIs
An extension that reads or writes orders must be tested with High-Performance Order Storage. Use WooCommerce order CRUD methods instead of directly reading or writing shop_order posts and post meta.
Declare HPOS compatibility only after testing it. If both legacy and HPOS storage are supported, both paths must produce the same result without duplicate writes.
Do not:
- query
wp_postsorwp_postmetafor orders when an order API exists; - assume an order-screen callback always receives a
WP_Post; - update an order meta value through one storage path and read it through another;
- claim HPOS support because a compatibility declaration was copied into the header.
19.3 Current WooCommerce interfaces
Test the components touched by the plugin, which may include:
- Cart and Checkout blocks;
- shortcode/classic cart and checkout when supported;
- HPOS;
- the current product editor;
- order admin screens;
- customer accounts;
- Store API and REST API behavior;
- WooCommerce Subscriptions or Bookings versions actually declared;
- multisite, multi-currency, tax and refund behavior when advertised.
If the plugin works only with classic checkout or another legacy interface, disclose that prominently.
19.4 Order, price, tax and payment integrity
Never trust product, variation, quantity, discount, tax, shipping, currency, commission, subscription, booking or total values submitted by the browser. Recalculate or retrieve authoritative values server-side.
Verify:
- order ownership;
- payment-session ownership;
- provider account;
- amount and currency;
- product and variation;
- remaining refundable amount;
- current order state;
- whether the operation was already processed.
Refund workflows must call the correct WooCommerce and gateway APIs, update marketplace/vendor accounting where applicable, prevent duplicate refunds and change local status only in a sequence that can recover safely from provider failure.
Inventory, bookings, license seats and capacity limits must be reserved atomically. A simple availability check followed by a later insert can overbook under concurrent requests.
19.5 Marketplace and multi-vendor integrations
When integrating with Dokan or another multi-vendor system:
- verify vendor ownership for every order, product, refund, note, export and report;
- use the platform’s supported accounting and commission APIs;
- update vendor balances and withdrawal availability correctly;
- prevent one seller from reading another seller’s customers or orders;
- document the exact supported platform and version;
- test administrator, vendor, staff and customer roles separately.
20. Specialized high-risk plugin categories
The following products are allowed, but their primary workflows receive deeper review.
20.1 Payment gateways, subscriptions, refunds and financial plugins
These plugins must:
- use the provider’s supported SDK or API;
- create and verify server-side payment sessions;
- verify signed webhooks;
- verify amount, currency, account, customer and order;
- prevent replay and duplicate fulfillment;
- handle asynchronous success, failure, cancellation, expiration, dispute and refund events;
- use idempotency keys where supported;
- never fulfill an order only because the browser reached a success URL;
- never permit a client-submitted “none” or alternate gateway value to bypass payment;
- avoid storing full card data or other prohibited payment credentials;
- document sandbox and production setup;
- maintain an auditable order lifecycle.
20.2 Booking, reservation, ticketing and inventory plugins
Availability must be enforced at write time, not only displayed earlier. Use database constraints, atomic updates, reservations with expiry, locks or another concurrency-safe design.
Validate time zones, date ranges, capacity, prices, cancellation rules and ownership. Hourly bookings must let the customer select a valid time rather than silently using the current time.
20.3 Upload, import, export and backup plugins
Apply the file, archive, authorization, privacy, SSRF and spreadsheet protections described earlier. Test large-but-supported files, partial failures, cancellation, cleanup, duplicate imports and restore behavior.
A backup feature must demonstrate that backups can be restored. Creating an archive alone is not a complete backup product.
20.4 AI and content-generation plugins
AI plugins must disclose:
- each provider used;
- whether the buyer supplies an API key;
- expected usage costs and limits;
- what site or customer data is sent;
- where prompts and generated output are stored;
- model limitations relevant to the feature;
- whether generated content is automatically published.
Validate and escape generated output. Do not treat model output as trusted code, SQL, HTML, a URL, a filename, a command or a factual authority.
Automatic publishing needs review, limits, error handling, duplicate prevention and a clear draft option. Plugins must not promise plagiarism-free, legally safe, factually correct or search-engine-guaranteed output.
20.5 Email, notification and automation plugins
Use queues for volume work, enforce limits, prevent duplicate sends, handle retries and distinguish transactional from marketing communication. Scheduled callbacks must load in cron context and must not mark a notification as sent when delivery was never attempted or clearly failed.
20.6 Security, maintenance, migration and remote-management plugins
These products must not weaken the site while claiming to protect it. Remote commands require strong authentication, strict authorization, replay protection, audit logs and narrow capabilities.
Malware scanners must not upload a buyer’s files to a third party without disclosure and permission. “Fix” actions need backups or a recovery path. Migration tools must not expose archives or credentials through public URLs.
20.7 Code execution, snippet and developer tools
Tools whose purpose is to execute administrator-provided code must restrict access to an appropriate high-trust capability, protect every action with a nonce, log changes safely and provide a recovery path for syntax errors.
They must not expose execution to unauthenticated users, lower roles, public REST routes or shared demo visitors. Remote code fetched from a URL must not be silently executed.
21. Demo and public provisioning security
A demo must never create a route into WPBay, the seller’s infrastructure or other demo visitors.
If visitors receive an administrator-like interface:
- each demo must be strongly isolated;
- file editing and file modifications must be disabled unless the environment is disposable and separately sandboxed against the host;
- plugin/theme installation and arbitrary uploads must be blocked;
- dangerous capabilities must be removed server-side, not merely hidden with CSS;
- credentials and environment secrets must not be shared with the demo;
- demos must expire and be cleaned up reliably;
- one visitor must not access another visitor’s instance or data.
Public provisioning endpoints must enforce:
- strict per-IP and broader capacity limits;
- server-side quotas;
- anti-automation controls appropriate to cost;
- maximum concurrent instances;
- authenticated internal provisioning calls;
- unpredictable instance identifiers;
- resource and execution limits;
- cleanup after failure;
- no user-controlled shell arguments, paths, database names, domains, package URLs or credentials.
A CAPTCHA alone is not sufficient protection for an expensive anonymous provisioning API.
22. Testing required before submission
The seller must test the final packaged ZIP, not only the development repository.
22.1 Minimum functional test
Test:
- installation from the submitted ZIP;
- activation on a clean site;
- activation with each required dependency missing;
- the complete primary workflow;
- settings save and reload;
- each user role that can access the plugin;
- invalid and unauthorized requests;
- deactivation and reactivation;
- uninstall behavior;
- update from the previous public version;
- JavaScript console and browser network errors;
WP_DEBUG,WP_DEBUG_LOGandSCRIPT_DEBUGwhere relevant;- scheduled actions by manually running the event;
- remote-service outage and invalid credentials;
- empty data and realistically large data;
- mobile and keyboard use for relevant interfaces.
For browser-facing interfaces, test current supported versions of Chrome, Firefox, Safari and Edge as relevant to the product. Test mobile Safari and Chrome when the public interface is responsive or intended for mobile use. A documented browser-specific limitation may be accepted when it is reasonable and disclosed; ordinary layouts and primary workflows must not break.
22.2 Compatibility matrix
Test the declared minimum and current environments as described earlier. For integrations, test both sides of every compatibility claim.
A WooCommerce plugin that declares HPOS, Cart and Checkout blocks, subscriptions, multi-currency or a marketplace integration must test those exact paths.
22.3 Automated checks
Before submission:
- run the current Plugin Check tool;
- run PHP_CodeSniffer with the WordPress Coding Standards;
- run a PHP compatibility ruleset against the declared minimum PHP version;
- lint PHP and JavaScript files;
- audit Composer and npm production dependencies;
- scan for credentials, malware indicators, debug artifacts and accidental development files.
Resolve substantive errors. If a result is a genuine false positive, document the reason or add the narrowest line-specific suppression with a meaningful explanation. Do not disable an entire security ruleset to make a report appear clean.
Automated tests are strongly recommended for all plugins and expected for complex or high-risk logic. Payment, refund, booking, inventory, migration, license and permission-sensitive workflows should have repeatable tests covering failure, concurrency, retries and duplicate events.
23. Common approval blockers
The following normally result in Changes required:
- missing capability or object-ownership checks;
- nonce-only authorization;
- unsafe REST, AJAX, webhook, upload or public provisioning endpoints;
- SQL injection, stored/reflected XSS, CSRF, SSRF, path traversal, insecure deserialization or arbitrary code execution;
- a core feature that is disconnected, simulated, disabled or broken;
- declared compatibility that was not implemented;
- PHP syntax newer than the declared minimum;
- version mismatches;
- broken activation, update, migration, cron or uninstall behavior;
- misleading product claims;
- undocumented external services or charges;
- an updater or license form that cannot serve WPBay buyers;
- serious N+1 queries, unbounded exports or resource-exhaustion paths;
- invalid package structure or missing runtime files;
- third-party code with unresolved license or known critical security problems;
- personal data exposure or hidden telemetry;
- a demo that grants dangerous access;
- common PHP warnings, fatal errors or JavaScript failures during normal use.
The following may result in immediate Rejection:
- malware, backdoors, credential theft, hidden remote control or destructive payloads;
- intentionally concealed executable behavior;
- cracked licensing or marketplace purchase-code bypasses;
- stolen products or absent selling rights;
- deliberate deception about the delivered functionality;
- an architecture whose central purpose is unsafe or abusive and cannot be corrected with a normal revision;
- repeated attempts to conceal previously identified dangerous behavior.
The following are not normally blockers by themselves:
- a small number of cosmetic PHPCS style warnings;
- a focused feature set that still provides credible buyer value;
- an expected and disclosed remote API intrinsic to the product;
- minified third-party production assets with clear source and licensing;
- benign encoding such as
base64_encode()used for a documented data format; - an optional enhancement that is not falsely advertised as included.
24. Seller pre-submission checklist
Before submitting, confirm all of the following:
- The uploaded ZIP is the exact installable production package.
- The plugin installs and activates on a clean site.
- The folder slug and main filename are stable.
- Header, readme, changelog, internal constants, WPBay version and updater version match.
- Minimum WordPress, PHP, WooCommerce and dependency versions are accurate.
- The plugin has been tested on the declared minimum and current environments.
- Plugin Check and WordPress Coding Standards have been run.
- Every form, AJAX action, REST route, webhook, upload and bulk action has the required authorization and validation.
- Nonces are used for CSRF protection and are not treated as authorization.
- Output is escaped in its final context.
- SQL is prepared, bounded, indexed and concurrency-safe where needed.
- Files, archives, imports, exports and remote URLs are handled safely.
- No credentials, customer data, logs, backups or development artifacts are included.
- External services, data transmission, accounts, charges and limits are disclosed.
- The plugin works when an external service is unavailable.
- Privacy, telemetry, retention, export and erasure behavior are documented.
- Cron and background jobs are registered, bounded, idempotent and tested.
- WooCommerce compatibility claims, including HPOS and checkout blocks, are genuinely tested.
- Licensing and updates work for WPBay customers.
- All third-party code and assets are licensed and documented.
- Documentation covers installation, setup, features, limitations, dependencies, troubleshooting, support and uninstall behavior.
- Screenshots and the product description match the submitted version.
- Every advertised feature is active and works end to end.
25. Related WPBay guidance
These requirements should be read together with:
- What Makes a Product WPBay-Ready?
- WordPress Plugins: Common Rejection Factors
- WPBay Seller Guidelines
Where those older pages contain outdated browser lists or general examples, the requirements on this page take precedence for plugin review.
26. Official development references
The following primary references are useful when preparing a submission:
- WordPress Plugin Developer Handbook
- WordPress Coding Standards
- Plugin header requirements
- WordPress plugin best practices
- WordPress plugin readme standard
- Validating data
- Sanitizing data
- Escaping data
- WordPress nonces
- User roles and capabilities
- Adding custom REST API endpoints
- Making HTTP requests
- Creating database tables with plugins
- WP-Cron
- Plugin uninstall methods
- WordPress plugin privacy guidance
- WordPress accessibility coding standards
- Internationalizing WordPress plugins
- Plugin Check
- WordPress Coding Standards for PHP_CodeSniffer
- WooCommerce extension compatibility guidance
- WooCommerce HPOS extension recipe book
Final note
WPBay’s goal is not to reject plugins for harmless formatting preferences or to force unnecessary complexity. The goal is to prevent buyers from receiving insecure, incomplete, misleading, incompatible, unmaintainable or legally questionable products.
If your implementation differs from a recommendation but is secure, testable, documented and appropriate for the product, explain that in the submission notes. If a requirement is unclear before submission, contact the WPBay review team.
