getreadystack commited on
Commit
881063c
·
verified ·
1 Parent(s): ab6b957

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +289 -17
index.html CHANGED
@@ -1,19 +1,291 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
6
+ <meta name="viewport" content="width=device-width,initial-scale=1">
7
+ <title>WP Plugin Review Gate — free online check</title>
8
+ <style>
9
+ :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
10
+ .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
11
+ textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
12
+ .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
13
+ input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
14
+ table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
15
+ .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
16
+ .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
17
+ </style>
18
+ <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
19
+ <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/wp-plugin-review-gate"></head>
20
+ <body>
21
+ <div class="wrap">
22
+ <h1>WP Plugin Review Gate</h1>
23
+ <p class="lede">Checks readme.txt and the main plugin header for the WordPress.org Plugin Review rules that send a submission or an update back to you. Runs entirely in your browser — nothing is uploaded.</p>
24
+ <textarea id="src" spellcheck="false">=== Speedy SEO Toolkit ===
25
+ Contributors: alexdev
26
+ Tags: seo, sitemap, schema, meta tags, performance
27
+ Requires at least: 6.9
28
+ Tested up to: 6.8.2
29
+ Stable tag: trunk
30
+ License: GPLv2 or later
31
+
32
+ Speedy SEO Toolkit adds sitemaps, schema output, meta tag control, redirects, breadcrumbs and a readable on-page score to your WordPress site, with no configuration needed at all.
33
+
34
+ == Description ==
35
+
36
+ Sitemaps, schema, meta tags and redirects in one plugin.
37
+
38
+ == Installation ==
39
+
40
+ 1. Upload the folder to wp-content/plugins.
41
+ 2. Activate the plugin.
42
+
43
+ == Changelog ==
44
+
45
+ = 2.4.1 =
46
+ * Faster sitemap generation.</textarea>
47
+ <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
48
+ <div id="out" aria-live="polite"></div>
49
+ <div id="paid"><strong>Free here:</strong> Flags every review blocker in the readme.txt or plugin header file you have open, with the line number and the exact header line to write instead.. <strong>In the editor:</strong> Audits the whole plugin folder in one pass - readme.txt against the plugin header across files, Stable tag against Version - and exports a dated submission report you keep. — that part asks for a licence key. <a href="https://buy.polar.sh/polar_cl_qArF3mNB1PwK3Pdmu8u0XW9Y9cxzGW2ytS3iq05dr5h" data-polar-checkout data-polar-checkout-theme="light">Whole-plugin sweep + dated submission report — $29 once</a><br><small>$29 once &middot; one licence key per person or team seat &middot; A freelance WordPress developer bills $30 to $90 an hour; a pre-submission read is an hour or two.</small></div>
50
+ <p class="note">Same engine as the VS Code extension, byte for byte.</p>
51
+ </div>
52
+ <script>var WPRG_RULES = [
53
+ {"id":"file_kind","scope":"any","sev":"info","title":"File not recognised","fix":"Open a readme.txt (starts with === Plugin Name ===) or the main plugin PHP file (header comment with Plugin Name:)."},
54
+ {"id":"readme_title_line","scope":"readme","sev":"error","title":"readme.txt does not start with === Plugin Name ===","fix":"Make the first non-empty line === Your Plugin Name ==="},
55
+ {"id":"stable_tag_missing","scope":"readme","sev":"error","title":"No Stable tag line","fix":"Stable tag: 1.0.0"},
56
+ {"id":"stable_tag_trunk","scope":"readme","sev":"error","title":"Stable tag: trunk ships trunk to every install","fix":"Stable tag: \u003cthe version you tagged\u003e"},
57
+ {"id":"requires_at_least_missing","scope":"readme","sev":"error","title":"No Requires at least line","fix":"Requires at least: 6.5"},
58
+ {"id":"requires_php_missing","scope":"readme","sev":"error","title":"No Requires PHP line","fix":"Requires PHP: 7.4"},
59
+ {"id":"tested_up_to_missing","scope":"readme","sev":"error","title":"No Tested up to line","fix":"Tested up to: 6.8"},
60
+ {"id":"tested_up_to_patch","scope":"readme","sev":"error","title":"Tested up to carries a patch number","fix":"Tested up to: \u003cmajor.minor only\u003e"},
61
+ {"id":"tested_below_requires","scope":"readme","sev":"error","title":"Tested up to is older than Requires at least","fix":"Raise Tested up to, or lower Requires at least"},
62
+ {"id":"short_description_long","scope":"readme","sev":"error","title":"Short description is over 150 characters","fix":"Cut the line under the header block to 150 characters"},
63
+ {"id":"tags_over_five","scope":"readme","sev":"warn","title":"More than five tags; only the first five are used","fix":"Keep five tags, the five you want to rank for"},
64
+ {"id":"license_line_missing","scope":"readme","sev":"error","title":"License or License URI missing","fix":"License: GPLv2 or later + License URI: https://www.gnu.org/licenses/gpl-2.0.html"},
65
+ {"id":"changelog_section_missing","scope":"readme","sev":"warn","title":"No == Changelog == section","fix":"Add == Changelog == with an entry for this version"},
66
+ {"id":"php_version_header_missing","scope":"php","sev":"error","title":"Plugin header has no Version","fix":"Version: 1.0.0 in the header comment"},
67
+ {"id":"php_requires_php_header_missing","scope":"php","sev":"error","title":"Plugin header has no Requires PHP","fix":"Requires PHP: 7.4 in the header comment"},
68
+ {"id":"php_license_header_missing","scope":"php","sev":"error","title":"Plugin header has no License line","fix":"License: GPLv2 or later in the header comment"},
69
+ {"id":"php_text_domain_missing","scope":"php","sev":"warn","title":"Plugin header has no Text Domain","fix":"Text Domain: \u003cyour plugin slug\u003e"},
70
+ {"id":"php_direct_access_guard","scope":"php","sev":"error","title":"No direct-access guard","fix":"defined( 'ABSPATH' ) || exit; under the header"},
71
+ {"id":"php_remote_asset","scope":"php","sev":"error","title":"Script or style enqueued from a remote URL","fix":"Ship the file inside the plugin and enqueue it with plugins_url()"},
72
+ {"id":"php_obfuscated_code","scope":"php","sev":"error","title":"eval, base64_decode or gzinflate in plugin code","fix":"Ship readable PHP; the review team reads every line"},
73
+ {"id":"php_hardcoded_plugin_path","scope":"php","sev":"warn","title":"Hard-coded wp-content/plugins path","fix":"plugin_dir_path() instead of the literal path"}
74
+ ]
75
+ ;</script>
76
+ <script>// WP Plugin Review Gate — one engine, used by the VS Code extension and by the free web page.
77
+ var RULES = (typeof module !== 'undefined' && module.exports) ? require('./rules.json') : window.WPRG_RULES;
78
+
79
+ var BY_ID = {};
80
+ for (var i = 0; i < RULES.length; i++) BY_ID[RULES[i].id] = RULES[i];
81
+
82
+ function lines(text) { return String(text == null ? '' : text).split(/\r\n|\r|\n/); }
83
+
84
+ function headerBlock(ls, isPhp) {
85
+ // readme.txt: the lines between the === title === line and the first blank line after it.
86
+ // plugin php: the lines of the first block comment that carries Plugin Name:.
87
+ var out = [], started = false;
88
+ for (var i = 0; i < ls.length && i < 80; i++) {
89
+ var l = ls[i];
90
+ if (isPhp) {
91
+ if (/^\s*\/\*/.test(l)) started = true;
92
+ if (started) out.push({ n: i + 1, t: l.replace(/^\s*\*+\s?/, '').replace(/^\s*\/\*+\s?/, '') });
93
+ if (started && /\*\//.test(l)) break;
94
+ } else {
95
+ if (/^\s*===\s*.+?\s*===\s*$/.test(l)) { started = true; continue; }
96
+ if (started) {
97
+ if (/^\s*$/.test(l)) break;
98
+ out.push({ n: i + 1, t: l });
99
+ }
100
+ }
101
+ }
102
+ return out;
103
+ }
104
+
105
+ function headerValue(block, key) {
106
+ var re = new RegExp('^\\s*' + key.replace(/ /g, '\\s+') + '\\s*:\\s*(.*)$', 'i');
107
+ for (var i = 0; i < block.length; i++) {
108
+ var m = re.exec(block[i].t);
109
+ if (m) return { value: m[1].trim(), line: block[i].n, raw: block[i].t.trim() };
110
+ }
111
+ return null;
112
+ }
113
+
114
+ function ver(v) {
115
+ var m = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(String(v || '').trim());
116
+ if (!m) return null;
117
+ return { major: +m[1], minor: m[2] ? +m[2] : 0, patch: m[3] === undefined ? null : +m[3] };
118
+ }
119
+ function cmp(a, b) { return (a.major - b.major) || (a.minor - b.minor); }
120
+
121
+ function add(out, id, msg, line) {
122
+ var r = BY_ID[id];
123
+ out.push({ check: id, sev: r ? r.sev : 'warn', msg: msg, line: line || 1 });
124
+ }
125
+
126
+ function kindOf(text, ls) {
127
+ var head = ls.slice(0, 80).join('\n');
128
+ if (/^\s*===\s*.+?\s*===\s*$/m.test(head) || /^\s*Stable\s+tag\s*:/im.test(head)) return 'readme';
129
+ if (/Plugin\s+Name\s*:/i.test(head) && (/<\?php/.test(head) || /^\s*\/\*/m.test(head))) return 'php';
130
+ return 'unknown';
131
+ }
132
+
133
+ function checkReadme(text, ls, out) {
134
+ var block = headerBlock(ls, false);
135
+ var firstLine = 1;
136
+ for (var i = 0; i < ls.length; i++) { if (ls[i].trim() !== '') { firstLine = i + 1; break; } }
137
+ if (!/^\s*===\s*.+?\s*===\s*$/.test(ls[firstLine - 1] || '')) {
138
+ add(out, 'readme_title_line', 'First line is "' + (ls[firstLine - 1] || '').trim().slice(0, 40) + '" — the directory reads the plugin name from === Your Plugin Name ===.', firstLine);
139
+ }
140
+
141
+ var stable = headerValue(block, 'Stable tag');
142
+ if (!stable) add(out, 'stable_tag_missing', 'No "Stable tag:" line — the directory has no version to ship, so the update never reaches installs. Write Stable tag: <the version you tagged>.', firstLine);
143
+ else if (/^trunk$/i.test(stable.value)) add(out, 'stable_tag_trunk', '"Stable tag: trunk" ships whatever sits in trunk to every install. Write the tagged version instead, e.g. Stable tag: 2.4.1.', stable.line);
144
+
145
+ var reqWp = headerValue(block, 'Requires at least');
146
+ if (!reqWp || !reqWp.value) add(out, 'requires_at_least_missing', 'No "Requires at least:" line — WordPress will offer your plugin to installs that cannot run it. Write Requires at least: 6.5.', firstLine);
147
+
148
+ var reqPhp = headerValue(block, 'Requires PHP');
149
+ if (!reqPhp || !reqPhp.value) add(out, 'requires_php_missing', 'No "Requires PHP:" line — every PHP version, including ones you never tested, is offered the plugin. Write Requires PHP: 7.4.', firstLine);
150
+
151
+ var tested = headerValue(block, 'Tested up to');
152
+ if (!tested || !tested.value) {
153
+ add(out, 'tested_up_to_missing', 'No "Tested up to:" line — the directory shows your plugin as untested. Write Tested up to: <the WordPress major you tested>.', firstLine);
154
+ } else {
155
+ var tv = ver(tested.value);
156
+ if (tv && tv.patch !== null) add(out, 'tested_up_to_patch', '"Tested up to: ' + tested.value + '" carries a patch number. The directory wants the major only: Tested up to: ' + tv.major + '.' + tv.minor + '.', tested.line);
157
+ if (tv && reqWp && reqWp.value) {
158
+ var rv = ver(reqWp.value);
159
+ if (rv && cmp(tv, rv) < 0) add(out, 'tested_below_requires', 'Tested up to ' + tv.major + '.' + tv.minor + ' is older than Requires at least ' + rv.major + '.' + rv.minor + ' — the two lines contradict each other and no install matches both.', tested.line);
160
+ }
161
+ }
162
+
163
+ var tags = headerValue(block, 'Tags');
164
+ if (tags && tags.value) {
165
+ var list = tags.value.split(',').map(function (s) { return s.trim(); }).filter(Boolean);
166
+ if (list.length > 5) add(out, 'tags_over_five', list.length + ' tags listed; only the first five are used, so "' + list.slice(5).join(', ') + '" does nothing.', tags.line);
167
+ }
168
+
169
+ var lic = headerValue(block, 'License');
170
+ var licUri = headerValue(block, 'License URI');
171
+ if (!lic || !licUri) {
172
+ var which = !lic && !licUri ? 'License and License URI are' : (!lic ? 'License is' : 'License URI is');
173
+ add(out, 'license_line_missing', which + ' missing from the header block. Add License: GPLv2 or later and License URI: https://www.gnu.org/licenses/gpl-2.0.html.', firstLine);
174
+ }
175
+
176
+ // short description = first non-empty line after the header block
177
+ var end = block.length ? block[block.length - 1].n : firstLine;
178
+ for (var j = end; j < ls.length; j++) {
179
+ var s = ls[j];
180
+ if (s.trim() === '') continue;
181
+ if (/^\s*==/.test(s)) break;
182
+ if (s.trim().length > 150) add(out, 'short_description_long', 'Short description is ' + s.trim().length + ' characters; the directory cuts it at 150.', j + 1);
183
+ break;
184
+ }
185
+
186
+ if (!/^\s*==\s*Changelog\s*==/im.test(text)) add(out, 'changelog_section_missing', 'No "== Changelog ==" section — reviewers and users read it to see what this version changed.', firstLine);
187
+ }
188
+
189
+ function checkPhp(text, ls, out) {
190
+ var block = headerBlock(ls, true);
191
+ var firstLine = block.length ? block[0].n : 1;
192
+
193
+ if (!headerValue(block, 'Version')) add(out, 'php_version_header_missing', 'The plugin header has no "Version:" line — WordPress cannot tell an update from the installed copy.', firstLine);
194
+ if (!headerValue(block, 'Requires PHP')) add(out, 'php_requires_php_header_missing', 'The plugin header has no "Requires PHP:" line — add Requires PHP: 7.4 so old installs are not offered the update.', firstLine);
195
+ if (!headerValue(block, 'License')) add(out, 'php_license_header_missing', 'The plugin header has no "License:" line — the directory only accepts GPL-compatible plugins. Add License: GPLv2 or later.', firstLine);
196
+ if (!headerValue(block, 'Text Domain')) add(out, 'php_text_domain_missing', 'The plugin header has no "Text Domain:" line — translations will not load. It must equal your plugin slug.', firstLine);
197
+
198
+ if (!/defined\s*\(\s*['"]ABSPATH['"]\s*\)/.test(text)) {
199
+ add(out, 'php_direct_access_guard', 'No ABSPATH guard in this file — the file runs when it is requested directly. Add defined( \'ABSPATH\' ) || exit; under the header.', firstLine);
200
+ }
201
+
202
+ for (var i = 0; i < ls.length; i++) {
203
+ var l = ls[i];
204
+ if (/wp_enqueue_(script|style)\s*\(/.test(l) && /https?:\/\/(?!localhost)/.test(l)) {
205
+ add(out, 'php_remote_asset', 'Line loads an asset from a remote URL: ' + l.trim().slice(0, 70) + ' — plugins in the directory must ship their own files.', i + 1);
206
+ }
207
+ var ob = /\b(eval|base64_decode|gzinflate|str_rot13)\s*\(/.exec(l);
208
+ if (ob) add(out, 'php_obfuscated_code', ob[1] + '() on this line reads as obfuscated code to a reviewer; ship readable PHP.', i + 1);
209
+ if (/['"][^'"]*wp-content\/plugins[^'"]*['"]/.test(l)) {
210
+ add(out, 'php_hardcoded_plugin_path', 'Hard-coded wp-content/plugins path — it breaks on every install that moved the plugins folder. Use plugin_dir_path().', i + 1);
211
+ }
212
+ }
213
+ }
214
+
215
+ function check(text, opts) {
216
+ opts = opts || {};
217
+ var ls = lines(text);
218
+ var out = [];
219
+ var kind = kindOf(text, ls);
220
+ if (kind === 'readme') checkReadme(text, ls, out);
221
+ else if (kind === 'php') checkPhp(text, ls, out);
222
+ else add(out, 'file_kind', 'This is neither a readme.txt (first line === Plugin Name ===) nor a main plugin file (header comment with Plugin Name:). Open one of those two files.', 1);
223
+ out.sort(function (a, b) { return a.line - b.line; });
224
+ return { findings: out, kind: kind, today: opts.today || '', rule_count: RULES.length };
225
+ }
226
+
227
+ var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
228
+ if (typeof module !== 'undefined' && module.exports) module.exports = API;
229
+ if (typeof window !== 'undefined') window.WPRGENGINE = API;
230
+ </script>
231
+ <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
232
+ 'use strict';
233
+ function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
234
+ function summaryLine(res) {
235
+ const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
236
+ return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
237
+ }
238
+ function toText(res, label) {
239
+ const f = (res && res.findings) || [];
240
+ const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
241
+ f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
242
+ return lines.join('\n');
243
+ }
244
+ function toHtml(res) {
245
+ const f = (res && res.findings) || [];
246
+ if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
247
+ const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
248
+ return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
249
+ }
250
+ var WPRGREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
251
+ if (typeof module !== 'undefined' && module.exports) module.exports = WPRGREPORT;
252
+ else window.WPRGREPORT = WPRGREPORT;
253
+ </script>
254
+ <script>
255
+ (function(){
256
+ var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
257
+ today.value=new Date().toISOString().slice(0,10);
258
+ function run(){ try { var res=window.WPRGENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.WPRGREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
259
+ go.onclick=run; if (src.value.trim()) run();
260
+ })();
261
+ </script>
262
+
263
+
264
+ <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.wp-plugin-review-gate" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'wp-plugin-review-gate',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/wp-plugin-review-gate" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'wp-plugin-review-gate',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/wp-plugin-review-gate" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'wp-plugin-review-gate',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/wp-plugin-review-gate" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'wp-plugin-review-gate',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.wp-plugin-review-gate
265
+ npx @readystack/wp-plugin-review-gate &lt;file&gt;
266
+ docker run --rm -v &quot;$PWD:/w&quot; getreadystack/wp-plugin-review-gate /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
267
+ <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 21 rules WP Plugin Review Gate checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"wp-plugin-review-gate",lang:"en",source:"rule_table"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>
268
+
269
+ <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">The readme.txt and plugin-header lines that send a wordpress.org submission back, found before you submit</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A freelance WordPress developer bills $30 to $90 an hour; a pre-submission read is an hour or two.</p><a href="https://buy.polar.sh/polar_cl_qArF3mNB1PwK3Pdmu8u0XW9Y9cxzGW2ytS3iq05dr5h" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
270
+ <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
271
+ <div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
272
+
273
+ <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
274
+
275
+ <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>
276
+ <section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-18">Updated 2026-09-18</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-18","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku97552_result_card.jpg" alt="WP Plugin Review Gate" loading="lazy" style="max-width:100%;border-radius:6px"></p>
277
+ <p>Six blockers in one readme.txt — that is what came back for a solo WordPress plugin developer in Porto who was one command away from submitting an SEO plugin to the wordpress.org directory. The PHP was fine. The header block was not:</p>
278
+ <p>=== Speedy SEO Toolkit === Contributors: alexdev Tags: seo, sitemap, schema, meta tags, performance Requires at least: 6.9 Tested up to: 6.8.2 Stable tag: trunk License: GPLv2 or later</p>
279
+ <p>Six things in those seven lines will either send the submission back or, quietly, stop the release from ever reaching the installs the plugin already has.</p>
280
+ <p><strong>Stable tag: trunk.</strong> This is the expensive one, and it does not look like an error. The directory serves whatever sits in trunk to every install. You tag 2.4.1, you push, you write the changelog — and users get trunk, which may be the half-finished commit from Tuesday. The fix is one word: Stable tag: 2.4.1.</p>
281
+ <p><strong>No Requires PHP line.</strong> Without it, WordPress offers the plugin to every PHP version there is. Requires PHP: 7.4.</p>
282
+ <p><strong>Tested up to: 6.8.2.</strong> The directory reads the major version only. A patch number in that field is not the compliment you think it is; write Tested up to: 6.8.</p>
283
+ <p><strong>Tested up to 6.8, Requires at least 6.9.</strong> Two lines that contradict each other: the plugin claims to need a WordPress newer than the newest one it was tested against, so no install satisfies both. One of the two numbers is wrong, and only you know which.</p>
284
+ <p><strong>A short description of 179 characters.</strong> That line is the one sentence shown on the plugin card. The directory cuts it at 150, mid-word, so 29 characters are gone.</p>
285
+ <p><strong>No License URI.</strong> License: GPLv2 or later is there; the URI line is not. The directory wants both, and a reviewer will ask.</p>
286
+ <p>None of these are code review. They are a reading of two files — readme.txt and the header comment at the top of the main plugin file — against the rules the wordpress.org Plugin Review Team reads them against. That is what WP Plugin Review Gate does: 21 rules, run on the file you have open in VS Code, each finding with a line number and the exact line to write instead. Run it on a clean readme.txt and it returns nothing at all.</p>
287
+ <p>The rest live in the plugin file: a header comment with no Version, no Requires PHP, no License or no Text Domain; no defined( &#x27;ABSPATH&#x27; ) || exit; guard; wp_enqueue_script() pointing at a remote URL instead of a file you ship; eval() or base64_decode(), which a reviewer reads as obfuscated code; a hard-coded wp-content/plugins path.</p>
288
+ <p>Why not ask an assistant? An assistant writes a fresh, plausible readme.txt from a prompt; it has never seen your file. It does not know your Stable tag says trunk, that Tested up to picked up a patch number, or that your short description grew to 179 characters. The check has to run on the file in front of you, and it has to count.</p>
289
+ <p>The free part is the whole file you have open — all 21 rules, every line number, in the editor or in the browser at getreadystack.com/tools/wp-plugin-review-gate, with nothing uploaded. The paid part is a different axis, not a crippled version of the same one: the whole plugin folder in one pass, readme.txt read against the plugin header, Stable tag checked against Version across files, and a dated report you keep for the submission. $29 once, one licence key per person or team seat, 7-day full refund.</p>
290
+ <p>A freelance WordPress developer bills $30 to $90 an hour; a pre-submission read is an hour or two. The readme takes four minutes to fix. The queue does not give the four minutes back.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku97552_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku97552_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does WP Plugin Review Gate actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads the readme.txt or the main plugin PHP file you have open and applies 21 rules the wordpress.org Plugin Review Team applies: Stable tag, Requires at least, Requires PHP, Tested up to, the 150-character short description, five tags, License lines, the ABSPATH guard, remote enqueues and obfuscated code. Each finding carries a line number and the replacement line.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Solo WordPress plugin developers and small agencies who publish to the wordpress.org directory, plus anyone maintaining an inherited plugin. If you have ever pushed an update and then found that Stable tag still said trunk, so the release never reached the installs you already had, this was written for you.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why is a free chatbot or a text editor not enough?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An assistant writes a plausible readme.txt from scratch; it cannot see the state of your file. It does not know your Stable tag says trunk, that Tested up to picked up a patch number, or that your short description grew to 179 characters against a 150-character cut. This runs on your file and counts.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what costs money?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no licence key: the file you have open is checked in full, all 21 rules, every line number, in the editor or in the browser. Paid: the whole plugin folder in one pass, readme.txt read against the plugin header and Stable tag against Version across files, plus a dated report you keep.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost me otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A freelance WordPress developer bills $30 to $90 an hour; a pre-submission read is an hour or two. The other price is time: a rejected submission goes back to the end of the review queue, and a wrong Stable tag means the version you released is not the version your users get.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does WP Plugin Review Gate actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads the readme.txt or the main plugin PHP file you have open and applies 21 rules the wordpress.org Plugin Review Team applies: Stable tag, Requires at least, Requires PHP, Tested up to, the 150-character short description, five tags, License lines, the ABSPATH guard, remote enqueues and obfuscated code. Each finding carries a line number and the replacement line."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "Solo WordPress plugin developers and small agencies who publish to the wordpress.org directory, plus anyone maintaining an inherited plugin. If you have ever pushed an update and then found that Stable tag still said trunk, so the release never reached the installs you already had, this was written for you."}}, {"@type": "Question", "name": "Why is a free chatbot or a text editor not enough?", "acceptedAnswer": {"@type": "Answer", "text": "An assistant writes a plausible readme.txt from scratch; it cannot see the state of your file. It does not know your Stable tag says trunk, that Tested up to picked up a patch number, or that your short description grew to 179 characters against a 150-character cut. This runs on your file and counts."}}, {"@type": "Question", "name": "What is free and what costs money?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no licence key: the file you have open is checked in full, all 21 rules, every line number, in the editor or in the browser. Paid: the whole plugin folder in one pass, readme.txt read against the plugin header and Stable tag against Version across files, plus a dated report you keep."}}, {"@type": "Question", "name": "What would this cost me otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "A freelance WordPress developer bills $30 to $90 an hour; a pre-submission read is an hour or two. The other price is time: a rejected submission goes back to the end of the review queue, and a wrong Stable tag means the version you released is not the version your users get."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:97552,slug:"wp-plugin-review-gate",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/payroll-wordpress-plugin"><span class="yj-rel-t">FLSA Payroll Timesheet Plugin for Small US Employers</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/maui-ios-submission-gate"><span class="yj-rel-t">MAUI iOS Submission Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/wordpress-ada-compliance-plugin"><span class="yj-rel-t">ADA Compliance Plugin for WordPress: Title II Grievance Form</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/charter-boat-booking-wordpress-plugin"><span class="yj-rel-t">Charter Boat Booking Requests — 6-Passenger Limit</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/membership-wordpress-plugin"><span class="yj-rel-t">Membership Plugin for WordPress: 20-Type Member &amp; Data-Request Desk for Clubs,</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/portfolio-wordpress-template"><span class="yj-rel-t">Portfolio WordPress Template: Commission Enquiry Plugin for Freelance Designer</span><span class="yj-rel-p">$129</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
291
  </html>