diff --git a/README.md b/README.md index a922ea5..b80d415 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Agent Skills solve this by giving AI assistants **expert-level WordPress knowled | **wp-phpstan** | PHPStan static analysis for WordPress projects (config, baselines, WP-specific typing) | | **wp-playground** | WordPress Playground for instant local environments | | **wpds** | WordPress Design System | +| **wp-plugin-directory-guidelines** | WordPress Plugin Directory Guidelines | | **blueprint** | WordPress Playground Blueprints for declarative Playground environment setup | ## Quick Start diff --git a/skills/wp-plugin-directory-guidelines/SKILL.md b/skills/wp-plugin-directory-guidelines/SKILL.md new file mode 100644 index 0000000..4fd6776 --- /dev/null +++ b/skills/wp-plugin-directory-guidelines/SKILL.md @@ -0,0 +1,132 @@ +--- +name: wp-plugin-directory-guidelines +description: "Use when reviewing WordPress plugins for GPL compliance, checking license headers or compatibility, evaluating upsell/freemium/trialware patterns, validating plugin naming or trademark rules, checking plugin slugs, understanding why a plugin was rejected from WordPress.org, or answering any question about the 18 WordPress.org Plugin Directory guidelines — even if the user doesn't mention 'guidelines' explicitly." +compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+)." +--- + +## Overview + +Authoritative reference for the 18 WordPress.org Plugin Directory guidelines. Covers GPL licensing, plugin naming/trademark rules, trialware restrictions, and all other submission requirements. + +## When to use + +Use this skill when you need to: +- Review a WordPress plugin for compliance with the WordPress.org Plugin Directory guidelines +- Check GPL license compatibility for a plugin or its bundled libraries +- Verify license headers in plugin files +- Identify common guideline violations before submission +- Answer questions about what is or is not allowed on WordPress.org +- Evaluate premium/upsell flows, license checks, or freemium positioning +- Review "teaser" or "preview" UI for trialware violations + +## Inputs required + +- Plugin source code (or specific files to review) +- Optional: plugin readme and plugin header metadata for naming and license checks + +## Procedure + +1. Check the plugin's license header against the **Valid License Headers** section below. +2. Walk through the **18 Guidelines** checklist, paying special attention to Guidelines 1, 4, 5, 7, 8, and 17. +3. Confirm trialware/freemium compliance using the checklist in [guideline-review-checklist.md](references/guideline-review-checklist.md) (Guideline 5 section). +4. For bundled third-party code, verify license compatibility against **GPL-Compatible Licenses (Quick)** below. +5. Flag matches from **Common GPL Violations (Quick)** below. +6. For edge cases, consult the detailed references and the [GNU GPL FAQ](https://www.gnu.org/licenses/gpl-faq.html). + +## 18-Guideline Review Checklist + +Use the detailed, per-guideline checklist in [guideline-review-checklist.md](references/guideline-review-checklist.md). Load this reference file only when a full guideline audit is requested. + +## GPL Compliance (Guideline 1 in Detail) + +Use [gpl-compliance.md](references/gpl-compliance.md) for full license tables, compatibility nuances, and examples. Keep this inline section as a quick decision aid. + +### Verification (Licensing) + +- Every licensing-related issue must cite **Guideline 1** and include the file path and exact license string. +- Confirm compatibility claims against **GPL-Compatible Licenses (Quick)** and escalate ambiguous licenses. + +### Failure modes (Licensing) + +- If a license is not clearly GPL-compatible, do not guess. Check the [GNU license list](https://www.gnu.org/licenses/license-list.html). +- For dual-license packages, verify both licenses and redistribution terms. + +### Quick Reference: WordPress GPL Requirements + +- WordPress is **GPLv2 or later**. +- Plugins distributed on WordPress.org must be 100% GPL-compatible (code and assets). +- Include a valid `License:` header and `License URI:` in the main plugin file. +- Do not add restrictions that conflict with GPL freedoms. + +### Valid License Headers + +## GPL Versions Summary + +| Version | Year | Key Addition | +|---------|------|--------------| +| GPLv1 | 1989 | Base copyleft: share-alike for modifications | +| GPLv2 | 1991 | "Liberty or death" clause (Section 7), clearer distribution terms | +| GPLv3 | 2007 | Anti-tivoization, explicit patent grants, compatibility provisions | + +WordPress uses **GPLv2 or later**, meaning plugins can use GPLv2, GPLv3, or "GPLv2 or later". + +For full license texts, see: +- [GNU General Public License v1](https://www.gnu.org/licenses/gpl-1.0.html) +- [GNU General Public License v2](https://www.gnu.org/licenses/gpl-2.0.html) +- [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html) + +## License Compliance Checklist + +When reviewing a plugin, verify: + +- [ ] Main plugin file has a valid `License:` header (e.g., `GPL-2.0-or-later`, `GPL-2.0+`, `GPLv2 or later`) +- [ ] Main plugin file has a `License URI:` header pointing to the GPL text +- [ ] If bundled libraries exist, each has a GPL-compatible license +- [ ] No "split licensing" (e.g., code GPL but premium features proprietary) +- [ ] No additional restrictions beyond what GPL allows +- [ ] No clauses restricting commercial use, modification, or redistribution +- [ ] No obfuscated code (violates the spirit of source code availability) + +## Valid License Headers for WordPress Plugins + +``` +License: GPL-2.0-or-later +License URI: https://www.gnu.org/licenses/gpl-2.0.html +``` + +```text +License: GPL-3.0-or-later +License URI: https://www.gnu.org/licenses/gpl-3.0.html +``` + +```text +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html +``` + +### GPL-Compatible Licenses (Quick) + +- Safe defaults: GPL-2.0-or-later, GPL-3.0-or-later. +- Commonly accepted permissive families: MIT/Expat, BSD, ISC, zlib, Boost. +- Conditional compatibility requires care: Apache-2.0 and MPL-2.0 (verify usage context). +- For full accepted and rejected identifiers, use [gpl-compliance.md](references/gpl-compliance.md). + +### Common GPL Violations (Quick) + +- Split licensing that restricts distributed code. +- Obfuscated or non-corresponding source distribution. +- Restrictive clauses (non-commercial, no-resale, forced backlink). +- Bundling GPL-incompatible libraries or assets. + +## Plugin Naming Rules (Guideline 17) + +Use [naming-rules.md](references/naming-rules.md) for full trademark lists, slug blocks, and naming examples. Keep this inline checklist for quick screening. + +### Naming Checklist (Quick) + +- Name is not a placeholder and has at least 5 alphanumeric characters. +- Header name and readme name match. +- Name is specific and function-related; avoid keyword stuffing. +- Trademark/project names appear only after connectors like `for`, `with`, `using`, `and`. +- No banned/discouraged terms or trademark portmanteaus. +- Slug is lowercase, hyphenated, <= 50 chars, and avoids blocked terms. diff --git a/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md b/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md new file mode 100644 index 0000000..7656fba --- /dev/null +++ b/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md @@ -0,0 +1,217 @@ +## GPL Compliance (Guideline 1 in Detail) + +### Verification (Licensing) + +- Every licensing-related issue must cite **Guideline 1** and include the specific file/license value found. +- License compatibility claims must match the GPL-Compatible Licenses table or the [GNU GPL-Compatible License List](https://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses). +- Use local `references/` files when present; otherwise use authoritative external URLs. + +### Failure modes (Licensing) + +- If a license is not listed in the compatibility tables, do not guess; check the [GNU license list](https://www.gnu.org/licenses/license-list.html) or escalate. +- If a plugin uses a dual-license model, verify both licenses independently. + + +### Quick Reference: WordPress GPL Requirements + +WordPress is licensed under **GPLv2 or later**. All plugins distributed via WordPress.org must be: + +1. **100% GPL-compatible** (code, images, CSS, and all assets) +2. Include a **license declaration** in the main plugin file header +3. Include the **full license text** or a URI reference to it +4. **Not restrict freedoms** granted by the GPL + +## GPL Versions Summary + +| Version | Year | Key Addition | +|---------|------|--------------| +| GPLv1 | 1989 | Base copyleft: share-alike for modifications | +| GPLv2 | 1991 | Patent clause (Section 7), clearer distribution terms | +| GPLv3 | 2007 | Anti-tivoization, explicit patent grants, compatibility provisions | + +WordPress uses **GPLv2 or later**, meaning plugins can use GPLv2, GPLv3, or "GPLv2 or later". + +For full license texts, see: +- [GNU General Public License v1](https://www.gnu.org/licenses/gpl-1.0.html) +- [GNU General Public License v2](https://www.gnu.org/licenses/gpl-2.0.html) +- [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html) + +## License Compliance Checklist + +When reviewing a plugin, verify: + +- [ ] Main plugin file has a valid `License:` header (e.g., `GPL-2.0-or-later`, `GPL-2.0+`, `GPLv2 or later`) +- [ ] Main plugin file has a `License URI:` header pointing to the GPL text +- [ ] If bundled libraries exist, each has a GPL-compatible license +- [ ] No "split licensing" (e.g., code GPL but premium features proprietary) +- [ ] No additional restrictions beyond what GPL allows +- [ ] No clauses restricting commercial use, modification, or redistribution +- [ ] No obfuscated code (violates the spirit of source code availability) + +## Valid License Headers for WordPress Plugins + +``` +License: GPL-2.0-or-later +License URI: https://www.gnu.org/licenses/gpl-2.0.html +``` + +``` +License: GPL-3.0-or-later +License URI: https://www.gnu.org/licenses/gpl-3.0.html +``` + +``` +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html +``` + +## Accepted Licenses by the WordPress.org Plugin Directory + +Source: [Plugin Check - License_Utils trait](https://github.com/WordPress/plugin-check/blob/trunk/includes/Traits/License_Utils.php) + +The Plugin Directory accepts licenses matching these identifiers (after normalization). The validation uses `is_license_gpl_compatible()` with the pattern: + +``` +GPL|GNU|LGPL|MIT|FreeBSD|New BSD|BSD-3-Clause|BSD 3 Clause|OpenLDAP|Expat|Apache2|MPL20|ISC|CC0|Unlicense|WTFPL|Artistic|Boost|NCSA|ZLib|X11 +``` + +### GPL Family (recommended) + +| Accepted Values | SPDX Identifier | License URI | +|-----------------|-----------------|-------------| +| `GPL-2.0-or-later`, `GPLv2 or later`, `GPL-2.0+` | GPL-2.0-or-later | https://www.gnu.org/licenses/gpl-2.0.html | +| `GPL-2.0-only`, `GPLv2` | GPL-2.0-only | https://www.gnu.org/licenses/gpl-2.0.html | +| `GPL-3.0-or-later`, `GPLv3 or later`, `GPL-3.0+` | GPL-3.0-or-later | https://www.gnu.org/licenses/gpl-3.0.html | +| `GPL-3.0-only`, `GPLv3` | GPL-3.0-only | https://www.gnu.org/licenses/gpl-3.0.html | +| `GNU General Public License` (any version text) | — | — | +| `LGPL-2.1`, `LGPLv2.1` | LGPL-2.1-or-later | https://www.gnu.org/licenses/lgpl-2.1.html | +| `LGPL-3.0`, `LGPLv3` | LGPL-3.0-or-later | https://www.gnu.org/licenses/lgpl-3.0.html | + +### Other GPL-Compatible Licenses Accepted + +| Identifier | License Name | Notes | +|------------|-------------|-------| +| `MIT` | MIT License | Permissive, compatible with GPLv2 and GPLv3 | +| `Expat` | Expat License | Functionally equivalent to MIT | +| `X11` | X11 License | Permissive; similar to Expat but with extra X Consortium clause | +| `FreeBSD` | BSD 2-Clause (FreeBSD) | Permissive, compatible with GPLv2 and GPLv3 | +| `New BSD`, `BSD-3-Clause`, `BSD 3 Clause` | BSD 3-Clause | Permissive, compatible with GPLv2 and GPLv3 | +| `Apache2`, `Apache-2.0` | Apache License 2.0 | Compatible with GPLv3 only (NOT GPLv2) | +| `MPL20`, `MPL-2.0` | Mozilla Public License 2.0 | Compatible via Section 3.3 | +| `ISC` | ISC License | Permissive, compatible with GPLv2 and GPLv3 | +| `OpenLDAP` | OpenLDAP Public License v2.7 | Permissive; older v2.3 is NOT compatible | +| `CC0` | Creative Commons Zero | Public domain dedication | +| `Unlicense` | The Unlicense | Public domain dedication | +| `WTFPL` | Do What The F*** You Want To Public License | Permissive, accepted in full text form too | +| `Artistic` | Artistic License 2.0 | Compatible via relicensing option in §4(c)(ii); Artistic 1.0 is NOT compatible | +| `Boost` | Boost Software License 1.0 | Lax permissive, compatible with GPLv2 and GPLv3 | +| `NCSA` | NCSA/University of Illinois Open Source License | Based on Expat + modified BSD; compatible with GPLv2 and GPLv3 | +| `ZLib` | zlib License | Permissive, compatible with GPLv2 and GPLv3 | + +### Licenses NOT Accepted + +Any license not matching the identifiers above will be rejected. Common rejections include: + +- **Proprietary / All Rights Reserved** +- **Creative Commons BY-NC** (NonCommercial restriction) +- **Creative Commons BY-ND** (NoDerivatives restriction) +- **Creative Commons BY-SA** (v3.0 and earlier; v4.0 is one-way compatible with GPLv3 but not in the Plugin Check regex) +- **JSON License** ("shall be used for Good, not Evil") +- **SSPL** (Server Side Public License) +- **BSL** (Business Source License) +- **Commons Clause** +- **Elastic License** +- **Original BSD (4-clause)** — advertising clause incompatible with GPL +- **MPL-1.0** — only MPL 2.0 is GPL-compatible +- **EPL** (Eclipse Public License) — weak copyleft, incompatible with GPL +- **EUPL** (European Union Public License) — copyleft incompatible with GPL without multi-step relicensing +- **Artistic License 1.0** — vague wording makes it incompatible; use 2.0 instead +- **OpenLDAP v2.3** (old) — incompatible; v2.7 is accepted + +## Common GPL Violations in Plugin Review + +### 1. Split Licensing +Plugin claims GPL but restricts premium features: +- "Free version is GPL, premium is proprietary" - **VIOLATION** +- All code distributed must be GPL-compatible + +### 2. Obfuscated Code +- Minified JavaScript is acceptable IF source is provided +- PHP obfuscation (ionCube, Zend Guard, etc.) - **VIOLATION** (prevents exercise of GPL freedoms) +- Encoded/encrypted PHP - **VIOLATION** + +### 3. Missing License Information +- No license header in main file +- No license file in the package +- Bundled libraries without license documentation + +### 4. Restrictive Clauses +- "You may not sell this plugin" - **VIOLATION** (GPL allows commercial redistribution) +- "You may not remove author credits" - Acceptable under GPLv3 Section 7(b), but not as blanket restriction +- "For personal use only" - **VIOLATION** +- "You must link back to our site" - **VIOLATION** (additional restriction) + +### 5. Incompatible Library Inclusion +- Including code under GPL-incompatible licenses +- Using assets (images, fonts, CSS) under restrictive licenses + +## Key GPL Concepts for Reviewers + +### Distribution vs. Private Use +- GPL obligations activate upon **distribution** (conveying to others) +- Private modifications do NOT trigger GPL requirements +- Publishing on WordPress.org IS distribution + +### Derivative Works +- A WordPress plugin that uses WordPress APIs is generally considered a derivative work +- Plugins that merely aggregate with WordPress may have different considerations +- When in doubt, the safe approach is GPL-compatible licensing + +### Source Code Requirement +- GPL requires access to "complete corresponding source code" +- For WordPress plugins: all PHP, JS source files, build scripts +- Minified files must have corresponding source available + +### The "Or Later" Clause +- "GPLv2 or later" allows users to choose GPLv2 OR any later version +- "GPLv2 only" means strictly GPLv2 (less flexible but valid) +- WordPress itself uses "GPLv2 or later" + +## Violation Reporting Workflow + +When a GPL violation is identified: + +1. **Document the violation** precisely: + - Product name and version + - Distributor information + - Specific license terms violated + - Evidence (screenshots, code snippets) + +2. **Contact the copyright holder** first +3. **Report to FSF** if the code is FSF-copyrighted: license-violation@gnu.org +4. **For WordPress.org plugins**: flag through the plugin review process + +## Frequently Asked Questions + +For comprehensive GPL FAQ answers, see the [GNU GPL FAQ](https://www.gnu.org/licenses/gpl-faq.html). + +Common questions during plugin review: + +**Can a plugin charge money and still be GPL?** +Yes. GPL allows charging for distribution. The requirement is that recipients get GPL freedoms (use, modify, redistribute). + +**Does a plugin need to include the full GPL text?** +GPLv2 Section 1 and GPLv3 Section 4 require giving recipients a copy of the license. A URI reference in the header plus including a LICENSE file is standard practice. + +**Can a plugin restrict who uses it?** +No. GPL explicitly prohibits additional restrictions on recipients. "For personal use only" or "non-commercial" clauses are incompatible. + +**Is minified JS without source a violation?** +If the plugin only distributes minified JS without any way to obtain the source, this conflicts with GPL's source code requirements. The source should be available (in the package or via a repository). + +**Can a plugin use CC-BY-SA images?** +CC-BY-SA 4.0 is one-way compatible with GPLv3 (CC-BY-SA material can be included in GPLv3 works). CC-BY-SA 3.0 is NOT compatible. + +**What about fonts bundled in plugins?** +Fonts must be under GPL-compatible licenses. Common acceptable font licenses: OFL (SIL Open Font License), Apache 2.0 (with GPLv3), MIT, GPL with font exception. + diff --git a/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md b/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md new file mode 100644 index 0000000..f511d0e --- /dev/null +++ b/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md @@ -0,0 +1,592 @@ +# WordPress.org Plugin Directory Guidelines — Review Checklist + +Source: [Detailed Plugin Guidelines](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/?output_format=md) + +Use this section as a structured checklist when reviewing a plugin. Each guideline includes the violation signal to look for, the verdict to issue, and the fix to recommend. Cite the guideline number in every finding. + +## Contents + +- [WordPress.org Plugin Directory Guidelines — Review Checklist](#wordpressorg-plugin-directory-guidelines--review-checklist) + - [Contents](#contents) + - [Guideline 1: GPL-Compatible License](#guideline-1-gpl-compatible-license) + - [Guideline 2: Developer Responsibility](#guideline-2-developer-responsibility) + - [Guideline 3: Stable Version in SVN](#guideline-3-stable-version-in-svn) + - [Guideline 4: Human-Readable Code](#guideline-4-human-readable-code) + - [Guideline 5: No Trialware](#guideline-5-no-trialware) + - [Guideline 6: SaaS Integrations Are Allowed — With Conditions](#guideline-6-saas-integrations-are-allowed--with-conditions) + - [Guideline 7: No External Data Collection Without Consent](#guideline-7-no-external-data-collection-without-consent) + - [Guideline 8: No Remotely Loaded Executable Code](#guideline-8-no-remotely-loaded-executable-code) + - [Guideline 9: No Illegal, Dishonest, or Offensive Behavior](#guideline-9-no-illegal-dishonest-or-offensive-behavior) + - [Guideline 10: No Forced External Links](#guideline-10-no-forced-external-links) + - [Guideline 11: No Admin Dashboard Hijacking](#guideline-11-no-admin-dashboard-hijacking) + - [Guideline 12: No Readme Spam](#guideline-12-no-readme-spam) + - [Guideline 13: Use WordPress-Bundled Libraries](#guideline-13-use-wordpress-bundled-libraries) + - [Guideline 14: SVN Is a Release Repository](#guideline-14-svn-is-a-release-repository) + - [Guideline 15: Increment Version Numbers](#guideline-15-increment-version-numbers) + - [Guideline 16: Plugin Must Be Complete at Submission](#guideline-16-plugin-must-be-complete-at-submission) + - [Guideline 17: Respect Trademarks and Copyrights](#guideline-17-respect-trademarks-and-copyrights) + - [Guideline 18: WordPress.org Reserves Directory Rights](#guideline-18-wordpressorg-reserves-directory-rights) + +--- + +### Guideline 1: GPL-Compatible License + +**Check:** Does the main plugin file have a `License:` header with a GPL-compatible value? Are all bundled third-party libraries under compatible licenses? + +**Violation signals:** +- Missing `License:` or `License URI:` header in the main plugin file +- License is `Proprietary`, `All Rights Reserved`, `CC-BY-NC`, `CC-BY-ND`, `SSPL`, `BSL`, `Commons Clause`, `EPL`, `EUPL`, or `MPL-1.0` +- Bundled library under a license not in the GPL-Compatible Licenses table (see below) +- PHP files encoded with ionCube, Zend Guard, or similar — source cannot be exercised → violation + +**Verdict:** Flag as **FAIL** with the specific file and license value found. + +**Fix:** Use `GPL-2.0-or-later` (recommended). Add full license text or a `License URI:` to `https://www.gnu.org/licenses/gpl-2.0.html`. Replace incompatible libraries. + +--- + +### Guideline 2: Developer Responsibility + +**Check:** Has the developer deliberately re-introduced previously removed code, circumvented a prior guideline decision, or included files they cannot legally distribute? + +**Violation signals:** +- Commit history shows restoring a file after it was removed by the review team +- Bundled assets with no documented license (treat as unlicensed until proven otherwise) +- Third-party API terms prohibit redistribution of the bundled SDK + +**Verdict:** Flag as **FAIL**. Document the specific file or commit. + +**Fix:** Remove the offending file or obtain and document proper licensing. + +--- + +### Guideline 3: Stable Version in SVN + +**Check:** Is the WordPress.org SVN version the canonical release? Is the plugin also distributed via an external channel with a newer version? + +**Violation signals:** +- `readme.txt` advertises a version not present in SVN trunk/tags +- External download page (developer's own site) offers a newer build than WP.org +- Plugin auto-updates itself from a non-WP.org server (also a Guideline 8 issue) + +**Verdict:** Flag as **FAIL** if an actively maintained external version is ahead of the directory. + +**Fix:** Keep SVN up to date. External channels may mirror but must not supersede the directory version. + +--- + +### Guideline 4: Human-Readable Code + +**Check:** Is all PHP, JS, and CSS in a form that a developer can read and understand? Are build sources available? + +**Violation signals:** +- PHP obfuscated with packer, eval+base64 chains, or variable names like `$a1b2c3` throughout +- Minified JS present **without** any source map or reference to the source repo/file in the readme +- Build artifacts (`.min.js`) committed with no corresponding unminified source in the package or a public repo linked from `readme.txt` + +**Verdict:** Flag as **FAIL** for obfuscated PHP (always). Flag minified-only JS as **FAIL** if no source access is documented. + +**Fix:** Remove obfuscation. Add a `Development` or `Build` section to `readme.txt` linking to the source repo (GitHub, GitLab, etc.). + +--- + +### Guideline 5: No Trialware + +**Core rule:** Every feature shipped in the directory must function end-to-end without a license key, payment, or account. + +**Check for each feature gate in the code:** + +1. Does a `has_paid_access()` / `is_licensed()` / `check_license()` check gate **local** processing (not an external service call)? +2. Is there a time-based expiry (`time() > $installed_at + 30 * DAY_IN_SECONDS`) for local behavior? +3. Is there a usage quota (`if ( $count >= 100 )`) that is artificially low and only exists to pressure upgrades? +4. Does the free user see a blocked/locked UI that prevents completing a core workflow? + +**Violation signals (flag as FAIL):** +- `return` / `wp_die()` / blocking screen shown when `has_paid_access()` is false for a local feature +- Ternary limits: `$limit = $licensed ? 10000 : 100` with no filter to extend the free cap +- Features expire after X days even when no external service is involved +- Admin screen is entirely replaced with an upgrade prompt + +**Allowed patterns (do not flag):** +- Upsell notice shown alongside a working free feature (non-blocking) +- Premium feature delegated to a **separate** add-on plugin not hosted on WP.org +- External SaaS feature gated because the **service** itself requires payment (e.g., AI API quota) +- Dismissible comparison table or upgrade button in plugin settings + +**Code patterns:** + +```php +// VIOLATION — local feature blocked by paid check +if ( ! $this->has_paid_access() ) { + echo 'Upgrade required'; + return; // ← blocks execution +} + +// VIOLATION — artificial cap with no extension point +$limit = $this->has_paid_access() ? 10000 : 100; +``` + +```php +// COMPLIANT — free path works; premium adds to it +$this->render_basic_export(); +if ( $this->has_premium_addon() ) { + do_action( 'myplugin_premium_export_options' ); +} + +// COMPLIANT — cap is consistent; extensible via filter +$limit = apply_filters( 'myplugin_event_limit', 10000 ); +``` + +**Pre-submission checklist:** +- [ ] All free features work without a license key +- [ ] No time-based expirations or usage quotas for local behavior +- [ ] No blocking/locked UI preventing free-tier workflows +- [ ] Upsell prompts are informational, non-blocking, and dismissible +- [ ] Premium-only code lives in a separate add-on or an external service + +--- + +### Guideline 6: SaaS Integrations Are Allowed — With Conditions + +**Check:** Does the external service provide real functionality? Is it documented in the readme? + +**Violation signals:** +- The external service's sole purpose is validating a license key; all actual processing is local +- Code was moved server-side specifically to disguise what is really a local feature gate +- Plugin is a storefront or checkout page for an external product with no real plugin functionality + +**Verdict:** Flag as **FAIL** for license-validation-only services. Do not flag genuine SaaS integrations. + +**Fix:** Document what the external service does in `readme.txt`. Move license validation out of the plugin's critical path if the functionality is local. + +--- + +### Guideline 7: No External Data Collection Without Consent + +**Check:** Does the plugin send any data to an external server without the user explicitly opting in? + +**Violation signals:** +- HTTP request to a remote URL on plugin activation, admin page load, or cron job with no user opt-in +- User email, site URL, or usage data sent without a visible opt-in checkbox or registration step +- Third-party analytics or ad-tracking scripts loaded in admin or frontend without consent +- Assets (images, fonts, scripts) loaded from an external CDN that are not the plugin's primary service + +**Exception:** Plugins that are interfaces to a named third-party service (e.g., Akismet, Mailchimp, a CDN) — consent is implied when the user configures the service connection. + +**Code patterns (violation vs compliant):** + +```php +// VIOLATION — sends data on activation without consent +register_activation_hook( __FILE__, function() { + wp_remote_post( + 'https://api.example.com/collect', + array( + 'body' => array( + 'site' => home_url(), + 'admin_email' => get_option( 'admin_email' ), + ), + ) + ); +} ); + +// COMPLIANT — explicit opt-in gate +if ( isset( $_POST['myplugin_opt_in'] ) && '1' === $_POST['myplugin_opt_in'] ) { + update_option( 'myplugin_tracking_opt_in', 1 ); +} + +if ( get_option( 'myplugin_tracking_opt_in' ) ) { + wp_remote_post( 'https://api.example.com/collect', $payload ); +} +``` + +**Review questions:** +1. Is any outbound request made on activation, first-run, or cron before consent is stored? +2. Is the opt-in UI explicit, unambiguous, and default-off? +3. Is consent persisted and checked before every telemetry request path? +4. Are collected fields documented in `readme.txt` privacy disclosures? + +**Verdict:** Flag as **FAIL** for any unconsented outbound call. Include the specific URL or domain found. + +**Fix:** Wrap all outbound calls in an opt-in gate. Add a `Privacy Policy` section to `readme.txt` describing what data is collected and why. + +**Pre-submission checklist:** +- [ ] No telemetry/analytics calls occur before explicit opt-in +- [ ] Opt-in control is visible and off by default +- [ ] Consent is stored and checked in every outbound path +- [ ] Privacy policy in readme explains data, destination, and purpose + +--- + +### Guideline 8: No Remotely Loaded Executable Code + +**Check:** Is all JS/CSS that runs on the user's site included in the plugin package? + +**Violation signals:** +- `wp_enqueue_script()` loading JS from a third-party CDN (not a self-hosted asset) +- Plugin fetches and executes code from an external URL at runtime (`file_get_contents` + `eval`, dynamic `