claude-plugin-wordpress-manager 1.5.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/CHANGELOG.md +97 -0
  3. package/README.md +27 -13
  4. package/agents/wp-accessibility-auditor.md +206 -0
  5. package/agents/wp-content-strategist.md +18 -0
  6. package/agents/wp-deployment-engineer.md +34 -2
  7. package/agents/wp-performance-optimizer.md +12 -0
  8. package/agents/wp-security-auditor.md +20 -0
  9. package/agents/wp-security-hardener.md +266 -0
  10. package/agents/wp-site-manager.md +14 -0
  11. package/agents/wp-test-engineer.md +207 -0
  12. package/docs/guides/INDEX.md +46 -0
  13. package/docs/guides/wp-blog.md +590 -0
  14. package/docs/guides/wp-design-system.md +976 -0
  15. package/docs/guides/wp-ecommerce.md +786 -0
  16. package/docs/guides/wp-landing-page.md +762 -0
  17. package/docs/guides/wp-portfolio.md +713 -0
  18. package/docs/plans/2026-02-27-design-system-guide-design.md +30 -0
  19. package/docs/plans/2026-02-27-site-type-guides-design.md +44 -0
  20. package/package.json +2 -2
  21. package/skills/wordpress-router/references/decision-tree.md +12 -2
  22. package/skills/wp-accessibility/SKILL.md +170 -0
  23. package/skills/wp-accessibility/references/a11y-audit-tools.md +248 -0
  24. package/skills/wp-accessibility/references/a11y-testing.md +222 -0
  25. package/skills/wp-accessibility/references/block-a11y.md +247 -0
  26. package/skills/wp-accessibility/references/interactive-a11y.md +272 -0
  27. package/skills/wp-accessibility/references/media-a11y.md +254 -0
  28. package/skills/wp-accessibility/references/theme-a11y.md +309 -0
  29. package/skills/wp-audit/SKILL.md +4 -0
  30. package/skills/wp-block-development/SKILL.md +5 -0
  31. package/skills/wp-block-themes/SKILL.md +4 -0
  32. package/skills/wp-e2e-testing/SKILL.md +186 -0
  33. package/skills/wp-e2e-testing/references/ci-integration.md +174 -0
  34. package/skills/wp-e2e-testing/references/jest-wordpress.md +114 -0
  35. package/skills/wp-e2e-testing/references/phpunit-wordpress.md +141 -0
  36. package/skills/wp-e2e-testing/references/playwright-wordpress.md +108 -0
  37. package/skills/wp-e2e-testing/references/test-data-generation.md +127 -0
  38. package/skills/wp-e2e-testing/references/visual-regression.md +107 -0
  39. package/skills/wp-e2e-testing/references/wp-env-setup.md +97 -0
  40. package/skills/wp-e2e-testing/scripts/test_inspect.mjs +375 -0
  41. package/skills/wp-headless/SKILL.md +168 -0
  42. package/skills/wp-headless/references/api-layer-choice.md +160 -0
  43. package/skills/wp-headless/references/cors-config.md +245 -0
  44. package/skills/wp-headless/references/frontend-integration.md +331 -0
  45. package/skills/wp-headless/references/headless-auth.md +286 -0
  46. package/skills/wp-headless/references/webhooks.md +277 -0
  47. package/skills/wp-headless/references/wpgraphql.md +331 -0
  48. package/skills/wp-headless/scripts/headless_inspect.mjs +321 -0
  49. package/skills/wp-i18n/SKILL.md +170 -0
  50. package/skills/wp-i18n/references/js-i18n.md +201 -0
  51. package/skills/wp-i18n/references/multilingual-setup.md +219 -0
  52. package/skills/wp-i18n/references/php-i18n.md +196 -0
  53. package/skills/wp-i18n/references/rtl-support.md +206 -0
  54. package/skills/wp-i18n/references/translation-workflow.md +178 -0
  55. package/skills/wp-i18n/references/wpcli-i18n.md +177 -0
  56. package/skills/wp-i18n/scripts/i18n_inspect.mjs +330 -0
  57. package/skills/wp-interactivity-api/SKILL.md +4 -0
  58. package/skills/wp-plugin-development/SKILL.md +6 -0
  59. package/skills/wp-rest-api/SKILL.md +4 -0
  60. package/skills/wp-security/SKILL.md +179 -0
  61. package/skills/wp-security/references/api-restriction.md +147 -0
  62. package/skills/wp-security/references/authentication-hardening.md +105 -0
  63. package/skills/wp-security/references/filesystem-hardening.md +105 -0
  64. package/skills/wp-security/references/http-headers.md +105 -0
  65. package/skills/wp-security/references/incident-response.md +144 -0
  66. package/skills/wp-security/references/user-capabilities.md +115 -0
  67. package/skills/wp-security/references/wp-config-security.md +129 -0
  68. package/skills/wp-security/scripts/security_inspect.mjs +393 -0
@@ -0,0 +1,196 @@
1
+ # PHP Internationalization
2
+
3
+ Use this file when internationalizing PHP code in WordPress plugins and themes.
4
+
5
+ ## Core translation functions
6
+
7
+ ### Simple strings
8
+
9
+ ```php
10
+ // Return translated string
11
+ $text = __('Hello World', 'my-text-domain');
12
+
13
+ // Echo translated string
14
+ _e('Hello World', 'my-text-domain');
15
+ ```
16
+
17
+ ### Strings with context
18
+
19
+ ```php
20
+ // "Post" as a verb vs noun
21
+ $verb = _x('Post', 'verb', 'my-text-domain');
22
+ $noun = _x('Post', 'noun', 'my-text-domain');
23
+
24
+ // Echo version
25
+ _ex('Post', 'verb', 'my-text-domain');
26
+ ```
27
+
28
+ ### Strings with variables
29
+
30
+ ```php
31
+ // Single placeholder
32
+ $text = sprintf(
33
+ /* translators: %s: user display name */
34
+ __('Welcome, %s!', 'my-text-domain'),
35
+ $user->display_name
36
+ );
37
+
38
+ // Multiple placeholders (use numbered)
39
+ $text = sprintf(
40
+ /* translators: 1: product name, 2: price */
41
+ __('%1$s costs %2$s', 'my-text-domain'),
42
+ $product_name,
43
+ $price
44
+ );
45
+ ```
46
+
47
+ ### Plurals
48
+
49
+ ```php
50
+ $text = sprintf(
51
+ /* translators: %d: number of items */
52
+ _n('%d item', '%d items', $count, 'my-text-domain'),
53
+ $count
54
+ );
55
+
56
+ // With context
57
+ $text = sprintf(
58
+ _nx('%d post', '%d posts', $count, 'blog posts', 'my-text-domain'),
59
+ $count
60
+ );
61
+ ```
62
+
63
+ ## Escaping functions
64
+
65
+ Always use escaping variants when outputting to HTML:
66
+
67
+ ```php
68
+ // Escape for HTML content
69
+ echo esc_html__('Safe text', 'my-text-domain');
70
+ esc_html_e('Safe text', 'my-text-domain');
71
+
72
+ // Escape for HTML attributes
73
+ echo esc_attr__('attribute value', 'my-text-domain');
74
+ esc_attr_e('attribute value', 'my-text-domain');
75
+
76
+ // With context
77
+ echo esc_html_x('Post', 'verb', 'my-text-domain');
78
+ ```
79
+
80
+ ### When to use which
81
+
82
+ | Context | Function |
83
+ |---------|----------|
84
+ | HTML content | `esc_html__()` / `esc_html_e()` |
85
+ | HTML attributes | `esc_attr__()` / `esc_attr_e()` |
86
+ | URLs | `esc_url()` around `__()` |
87
+ | JavaScript strings | `esc_js()` around `__()` |
88
+ | Already-safe internal use | `__()` / `_e()` |
89
+
90
+ ## Text domain loading
91
+
92
+ ### Plugins
93
+
94
+ ```php
95
+ add_action('init', function() {
96
+ load_plugin_textdomain(
97
+ 'my-text-domain',
98
+ false,
99
+ dirname(plugin_basename(__FILE__)) . '/languages'
100
+ );
101
+ });
102
+ ```
103
+
104
+ ### Themes
105
+
106
+ ```php
107
+ add_action('after_setup_theme', function() {
108
+ load_theme_textdomain(
109
+ 'my-text-domain',
110
+ get_template_directory() . '/languages'
111
+ );
112
+ });
113
+
114
+ // Child theme
115
+ add_action('after_setup_theme', function() {
116
+ load_child_theme_textdomain(
117
+ 'my-child-domain',
118
+ get_stylesheet_directory() . '/languages'
119
+ );
120
+ });
121
+ ```
122
+
123
+ ### WordPress 6.7+ (automatic loading)
124
+
125
+ Since WordPress 6.7, translation files placed in `wp-content/languages/plugins/` or `wp-content/languages/themes/` are loaded automatically. Manual `load_plugin_textdomain()` is still recommended as a fallback.
126
+
127
+ ## Common mistakes
128
+
129
+ ### Do NOT concatenate translatable strings
130
+
131
+ ```php
132
+ // WRONG — translators cannot reorder
133
+ __('There are ' . $count . ' items', 'my-text-domain');
134
+
135
+ // CORRECT
136
+ sprintf(__('There are %d items', 'my-text-domain'), $count);
137
+ ```
138
+
139
+ ### Do NOT use variables as text domain
140
+
141
+ ```php
142
+ // WRONG — tools cannot extract
143
+ __('Hello', $domain);
144
+
145
+ // CORRECT — literal string only
146
+ __('Hello', 'my-text-domain');
147
+ ```
148
+
149
+ ### Do NOT translate HTML
150
+
151
+ ```php
152
+ // WRONG — HTML in translatable string
153
+ __('<strong>Warning:</strong> This is dangerous', 'my-text-domain');
154
+
155
+ // CORRECT — separate HTML from text
156
+ '<strong>' . esc_html__('Warning:', 'my-text-domain') . '</strong> '
157
+ . esc_html__('This is dangerous', 'my-text-domain');
158
+ ```
159
+
160
+ ### Do NOT split sentences
161
+
162
+ ```php
163
+ // WRONG — sentence split across calls
164
+ __('Click ', 'my-text-domain') . '<a>' . __('here', 'my-text-domain') . '</a>';
165
+
166
+ // CORRECT — full sentence with placeholder
167
+ sprintf(
168
+ /* translators: %s: link HTML */
169
+ __('Click %s for details', 'my-text-domain'),
170
+ '<a href="...">' . esc_html__('here', 'my-text-domain') . '</a>'
171
+ );
172
+ ```
173
+
174
+ ## Translator comments
175
+
176
+ Add context for translators with `/* translators: */` comments:
177
+
178
+ ```php
179
+ /* translators: %s: date in ISO 8601 format */
180
+ sprintf(__('Published on %s', 'my-text-domain'), $date);
181
+
182
+ /* translators: 1: opening link tag, 2: closing link tag */
183
+ sprintf(__('Read the %1$sfull article%2$s', 'my-text-domain'), '<a href="...">', '</a>');
184
+ ```
185
+
186
+ These comments must appear on the line immediately before the translation function call.
187
+
188
+ ## Verification
189
+
190
+ ```bash
191
+ # Check for missing text domains
192
+ wp i18n make-pot . languages/my-text-domain.pot --slug=my-text-domain
193
+
194
+ # Audit for untranslated strings
195
+ grep -rn "echo \"\|echo '" --include="*.php" | grep -v "__\|_e\|esc_"
196
+ ```
@@ -0,0 +1,206 @@
1
+ # RTL (Right-to-Left) Support
2
+
3
+ Use this file when adding right-to-left language support to WordPress themes and plugins.
4
+
5
+ ## RTL languages
6
+
7
+ Arabic (`ar`), Hebrew (`he`), Persian/Farsi (`fa`), Urdu (`ur`), Pashto (`ps`), Sindhi (`sd`), Kurdish (Sorani) (`ckb`), Uyghur (`ug`), Divehi (`dv`).
8
+
9
+ ## How WordPress handles RTL
10
+
11
+ WordPress automatically:
12
+ 1. Sets `dir="rtl"` on `<html>` when the locale is RTL
13
+ 2. Adds `class="rtl"` to `<body>`
14
+ 3. Loads `*-rtl.css` stylesheets (if they exist) instead of `*.css`
15
+
16
+ Check direction in PHP:
17
+ ```php
18
+ if (is_rtl()) {
19
+ // RTL-specific logic
20
+ }
21
+ ```
22
+
23
+ Check in JavaScript:
24
+ ```js
25
+ const isRtl = document.documentElement.dir === 'rtl';
26
+ // or
27
+ const isRtl = document.body.classList.contains('rtl');
28
+ ```
29
+
30
+ ## CSS approach: Logical properties (recommended)
31
+
32
+ Modern CSS logical properties handle both LTR and RTL automatically:
33
+
34
+ ```css
35
+ /* AVOID physical properties */
36
+ .card {
37
+ margin-left: 20px; /* LTR only */
38
+ padding-right: 10px; /* LTR only */
39
+ text-align: left; /* LTR only */
40
+ float: left; /* LTR only */
41
+ border-left: 1px solid; /* LTR only */
42
+ }
43
+
44
+ /* USE logical properties */
45
+ .card {
46
+ margin-inline-start: 20px; /* left in LTR, right in RTL */
47
+ padding-inline-end: 10px; /* right in LTR, left in RTL */
48
+ text-align: start; /* left in LTR, right in RTL */
49
+ float: inline-start; /* left in LTR, right in RTL */
50
+ border-inline-start: 1px solid; /* left in LTR, right in RTL */
51
+ }
52
+ ```
53
+
54
+ ### Logical property mapping
55
+
56
+ | Physical | Logical | LTR | RTL |
57
+ |----------|---------|-----|-----|
58
+ | `left` | `inline-start` | left | right |
59
+ | `right` | `inline-end` | right | left |
60
+ | `margin-left` | `margin-inline-start` | margin-left | margin-right |
61
+ | `margin-right` | `margin-inline-end` | margin-right | margin-left |
62
+ | `padding-left` | `padding-inline-start` | padding-left | padding-right |
63
+ | `padding-right` | `padding-inline-end` | padding-right | padding-left |
64
+ | `border-left` | `border-inline-start` | border-left | border-right |
65
+ | `text-align: left` | `text-align: start` | left | right |
66
+ | `float: left` | `float: inline-start` | left | right |
67
+
68
+ ### Shorthand
69
+
70
+ ```css
71
+ /* Physical: top right bottom left */
72
+ margin: 10px 20px 10px 0;
73
+
74
+ /* Logical */
75
+ margin-block: 10px; /* top and bottom */
76
+ margin-inline: 0 20px; /* start and end */
77
+ ```
78
+
79
+ ## CSS approach: RTL stylesheets (legacy)
80
+
81
+ ### Automatic RTL generation
82
+
83
+ ```bash
84
+ # Generate RTL stylesheets with rtlcss
85
+ npx rtlcss style.css style-rtl.css
86
+
87
+ # Watch mode
88
+ npx rtlcss -w src/style.css dist/style-rtl.css
89
+ ```
90
+
91
+ ### rtlcss directives
92
+
93
+ Control flipping with comments:
94
+
95
+ ```css
96
+ /* rtl:ignore — skip this rule */
97
+ .icon-arrow {
98
+ /* rtl:ignore */
99
+ transform: rotate(45deg);
100
+ }
101
+
102
+ /* rtl:remove — remove this rule in RTL */
103
+ .ltr-only {
104
+ /* rtl:remove */
105
+ float: left;
106
+ }
107
+
108
+ /* rtl:raw — insert raw CSS in RTL */
109
+ .custom {
110
+ /* rtl:raw:
111
+ float: right;
112
+ */
113
+ }
114
+ ```
115
+
116
+ ### Enqueuing RTL stylesheets
117
+
118
+ WordPress handles this automatically when you enqueue properly:
119
+
120
+ ```php
121
+ wp_enqueue_style('my-style', plugins_url('css/style.css', __FILE__));
122
+ // WordPress will automatically load css/style-rtl.css in RTL contexts
123
+ // IF the RTL file exists in the same directory
124
+ ```
125
+
126
+ For custom paths:
127
+ ```php
128
+ wp_style_add_data('my-style', 'rtl', 'replace');
129
+ // WordPress will load style-rtl.css instead of style.css
130
+ ```
131
+
132
+ Or add an independent RTL stylesheet:
133
+ ```php
134
+ wp_style_add_data('my-style', 'rtl', plugin_dir_url(__FILE__) . 'css/custom-rtl.css');
135
+ ```
136
+
137
+ ## Block editor RTL support
138
+
139
+ ### Block styles
140
+
141
+ ```css
142
+ /* Use logical properties in block stylesheets */
143
+ .wp-block-my-plugin-card {
144
+ padding-inline-start: 1rem;
145
+ border-inline-start: 3px solid var(--wp--preset--color--primary);
146
+ }
147
+ ```
148
+
149
+ ### useBlockProps and direction
150
+
151
+ ```js
152
+ import { useBlockProps } from '@wordpress/block-editor';
153
+
154
+ export default function Edit() {
155
+ const blockProps = useBlockProps();
156
+ // blockProps automatically inherits the document direction
157
+ return <div {...blockProps}>Content</div>;
158
+ }
159
+ ```
160
+
161
+ ## Icons and directional elements
162
+
163
+ Flip directional icons in RTL:
164
+
165
+ ```css
166
+ /* Arrows, chevrons, navigation icons */
167
+ .rtl .icon-arrow-right {
168
+ transform: scaleX(-1);
169
+ }
170
+
171
+ /* Or with logical approach */
172
+ [dir="rtl"] .icon-next {
173
+ transform: scaleX(-1);
174
+ }
175
+ ```
176
+
177
+ Do NOT flip:
178
+ - Clocks (always clockwise)
179
+ - Media playback controls (play/pause universal)
180
+ - Checkmarks
181
+ - Phone icons
182
+ - Logos and brand marks
183
+
184
+ ## Testing RTL
185
+
186
+ ```bash
187
+ # Switch site to Arabic
188
+ wp site switch-language ar
189
+
190
+ # Switch back to English
191
+ wp site switch-language en_US
192
+ ```
193
+
194
+ Quick browser test: add `dir="rtl"` to `<html>` in DevTools.
195
+
196
+ WordPress admin: Settings → General → Site Language → Arabic (or any RTL language).
197
+
198
+ ## Verification checklist
199
+
200
+ - [ ] All CSS uses logical properties (or RTL stylesheets exist)
201
+ - [ ] No hardcoded `left`/`right` in positioning
202
+ - [ ] Directional icons flip correctly
203
+ - [ ] Text alignment uses `start`/`end` not `left`/`right`
204
+ - [ ] Flexbox/Grid layout respects direction
205
+ - [ ] RTL stylesheets are properly enqueued with `wp_style_add_data`
206
+ - [ ] Tested with at least one RTL locale (Arabic recommended)
@@ -0,0 +1,178 @@
1
+ # Translation Workflow
2
+
3
+ Use this file when managing the .pot/.po/.mo translation file lifecycle.
4
+
5
+ ## File types
6
+
7
+ | File | Purpose | Format |
8
+ |------|---------|--------|
9
+ | `.pot` | Template — master list of all translatable strings | Portable Object Template |
10
+ | `.po` | Translation — human-editable translations for a locale | Portable Object |
11
+ | `.mo` | Compiled — binary version loaded by PHP at runtime | Machine Object |
12
+ | `.json` | JS translations — JED format for `@wordpress/i18n` | JSON |
13
+
14
+ ## Directory structure
15
+
16
+ ```
17
+ my-plugin/
18
+ ├── languages/
19
+ │ ├── my-text-domain.pot # Template
20
+ │ ├── my-text-domain-it_IT.po # Italian translations
21
+ │ ├── my-text-domain-it_IT.mo # Compiled Italian
22
+ │ ├── my-text-domain-it_IT-{hash}.json # JS Italian translations
23
+ │ └── my-text-domain-de_DE.po # German translations
24
+ ```
25
+
26
+ Naming convention: `{text-domain}-{locale}.{ext}`
27
+
28
+ Common locales: `it_IT`, `de_DE`, `fr_FR`, `es_ES`, `pt_BR`, `ja`, `zh_CN`, `ar`
29
+
30
+ ## Step 1: Generate POT file
31
+
32
+ ```bash
33
+ # From plugin root
34
+ wp i18n make-pot . languages/my-text-domain.pot
35
+
36
+ # With options
37
+ wp i18n make-pot . languages/my-text-domain.pot \
38
+ --slug=my-plugin \
39
+ --domain=my-text-domain \
40
+ --include="src/,includes/" \
41
+ --exclude="node_modules/,vendor/,tests/" \
42
+ --headers='{"Report-Msgid-Bugs-To":"https://github.com/user/repo/issues"}'
43
+ ```
44
+
45
+ The `make-pot` command scans:
46
+ - PHP files for `__()`, `_e()`, `esc_html__()`, etc.
47
+ - JS/JSX files for `@wordpress/i18n` calls
48
+ - `block.json` files for translatable fields (title, description, keywords)
49
+
50
+ ## Step 2: Create/update PO files
51
+
52
+ ### From scratch
53
+
54
+ ```bash
55
+ # Create a new PO file for Italian
56
+ msginit --input=languages/my-text-domain.pot \
57
+ --output-file=languages/my-text-domain-it_IT.po \
58
+ --locale=it_IT
59
+ ```
60
+
61
+ ### Update existing PO with new strings
62
+
63
+ ```bash
64
+ # Merge new POT into existing PO (preserves existing translations)
65
+ wp i18n update-po languages/my-text-domain.pot languages/
66
+ ```
67
+
68
+ Or with `msgmerge`:
69
+ ```bash
70
+ msgmerge --update languages/my-text-domain-it_IT.po languages/my-text-domain.pot
71
+ ```
72
+
73
+ ## Step 3: Translate
74
+
75
+ ### Using a PO editor
76
+
77
+ Recommended tools:
78
+ - **Poedit** (desktop, free + pro) — the standard tool
79
+ - **GlotPress** (web-based, used by WordPress.org)
80
+ - **Loco Translate** (WordPress plugin, in-dashboard editing)
81
+
82
+ ### PO file format
83
+
84
+ ```po
85
+ #: src/includes/class-main.php:42
86
+ #. translators: %s: site name
87
+ msgid "Welcome to %s"
88
+ msgstr "Benvenuto su %s"
89
+
90
+ #: src/includes/class-main.php:55
91
+ msgid "Save Changes"
92
+ msgstr "Salva Modifiche"
93
+
94
+ #: src/includes/class-main.php:60
95
+ msgctxt "verb"
96
+ msgid "Post"
97
+ msgstr "Pubblica"
98
+
99
+ #: src/includes/class-main.php:70
100
+ msgid "%d item"
101
+ msgid_plural "%d items"
102
+ msgstr[0] "%d elemento"
103
+ msgstr[1] "%d elementi"
104
+ ```
105
+
106
+ ## Step 4: Compile MO files
107
+
108
+ ```bash
109
+ # Compile all PO files to MO
110
+ wp i18n make-mo languages/
111
+
112
+ # Or with msgfmt
113
+ msgfmt languages/my-text-domain-it_IT.po -o languages/my-text-domain-it_IT.mo
114
+ ```
115
+
116
+ ## Step 5: Generate JSON for JavaScript
117
+
118
+ ```bash
119
+ # Generate JSON from PO files (for wp_set_script_translations)
120
+ wp i18n make-json languages/ --no-purge
121
+ ```
122
+
123
+ `--no-purge` keeps the JS strings in the PO file (useful if you also use them server-side).
124
+
125
+ ## Automation: Build script integration
126
+
127
+ ### package.json
128
+
129
+ ```json
130
+ {
131
+ "scripts": {
132
+ "i18n:pot": "wp i18n make-pot . languages/my-text-domain.pot --exclude=node_modules/,vendor/",
133
+ "i18n:update": "wp i18n update-po languages/my-text-domain.pot languages/",
134
+ "i18n:mo": "wp i18n make-mo languages/",
135
+ "i18n:json": "wp i18n make-json languages/ --no-purge",
136
+ "i18n:build": "npm run i18n:pot && npm run i18n:update && npm run i18n:mo && npm run i18n:json"
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Pre-release checklist
142
+
143
+ 1. Run `wp i18n make-pot` to capture all new strings
144
+ 2. Run `wp i18n update-po` to merge into existing translations
145
+ 3. Send updated PO files to translators
146
+ 4. Compile MO files after translations are complete
147
+ 5. Generate JSON files for JS strings
148
+ 6. Test each locale by switching `WPLANG` in `wp-config.php`
149
+
150
+ ## WordPress.org translation (GlotPress)
151
+
152
+ For plugins/themes hosted on WordPress.org:
153
+ 1. Set `Text Domain` and `Domain Path` in the plugin header
154
+ 2. Upload the POT file to SVN `trunk/languages/`
155
+ 3. Translations are crowdsourced via translate.wordpress.org
156
+ 4. Users receive translations automatically via WordPress updates
157
+
158
+ Plugin header:
159
+ ```php
160
+ /**
161
+ * Plugin Name: My Plugin
162
+ * Text Domain: my-text-domain
163
+ * Domain Path: /languages
164
+ */
165
+ ```
166
+
167
+ ## Verification
168
+
169
+ ```bash
170
+ # Check PO file for errors
171
+ msgfmt --check languages/my-text-domain-it_IT.po
172
+
173
+ # Count translated/untranslated strings
174
+ msgfmt --statistics languages/my-text-domain-it_IT.po
175
+
176
+ # Verify text domain consistency
177
+ grep -rn "__('" --include="*.php" src/ | grep -v "'my-text-domain'"
178
+ ```