@10up/block-renderer-patterns 0.1.4

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.
package/README.md ADDED
@@ -0,0 +1,284 @@
1
+ # @10up/block-renderer-patterns
2
+
3
+ Scan WordPress theme pattern directories and parse PHP file headers to extract pattern metadata and content.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @10up/block-renderer-patterns
9
+ # or
10
+ pnpm add @10up/block-renderer-patterns
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ WordPress themes can define [block patterns](https://developer.wordpress.org/themes/patterns/) in PHP files within the `/patterns` directory. This package:
16
+
17
+ 1. **Scans pattern directories** - Both `/patterns` and `/synced-patterns`
18
+ 2. **Parses PHP headers** - Extracts metadata from PHP file docblocks
19
+ 3. **Extracts block content** - Gets the actual block markup
20
+ 4. **Creates a searchable registry** - Query patterns by category, block type, or keywords
21
+
22
+ ## Usage
23
+
24
+ ### Load All Patterns from Theme
25
+
26
+ The main entry point - loads all patterns and returns a registry:
27
+
28
+ ```typescript
29
+ import { loadPatterns } from '@10up/block-renderer-patterns';
30
+
31
+ const registry = loadPatterns('/path/to/theme');
32
+
33
+ // Iterate over all patterns
34
+ for (const [slug, pattern] of registry) {
35
+ console.log(pattern.slug); // 'theme-name/hero-section'
36
+ console.log(pattern.title); // 'Hero Section'
37
+ console.log(pattern.categories); // ['featured', 'banner']
38
+ console.log(pattern.content); // '<!-- wp:group -->...'
39
+ }
40
+
41
+ // Get a specific pattern
42
+ const heroPattern = registry.get('theme-name/hero-section');
43
+ ```
44
+
45
+ ### Scan Patterns with Error Reporting
46
+
47
+ Get detailed scan results including errors:
48
+
49
+ ```typescript
50
+ import { scanPatterns, createPatternRegistry } from '@10up/block-renderer-patterns';
51
+
52
+ const result = scanPatterns('/path/to/theme');
53
+
54
+ // Check for errors
55
+ if (result.errors.length > 0) {
56
+ console.log('Failed to parse:');
57
+ for (const error of result.errors) {
58
+ console.log(` ${error.filePath}: ${error.error}`);
59
+ }
60
+ }
61
+
62
+ // Access successfully parsed patterns
63
+ console.log(`Found ${result.patterns.length} patterns`);
64
+
65
+ // Create a registry from results
66
+ const registry = createPatternRegistry(result);
67
+ ```
68
+
69
+ ### Parse Single Pattern File
70
+
71
+ ```typescript
72
+ import { parsePatternFile } from '@10up/block-renderer-patterns';
73
+
74
+ const pattern = parsePatternFile(
75
+ '/path/to/theme/patterns/hero.php',
76
+ 'theme-name', // Theme name for slug prefix
77
+ false // isSynced flag
78
+ );
79
+
80
+ console.log(pattern);
81
+ // {
82
+ // slug: 'theme-name/hero',
83
+ // title: 'Hero Section',
84
+ // description: 'A hero section with...',
85
+ // categories: ['featured'],
86
+ // keywords: ['hero', 'banner'],
87
+ // blockTypes: ['core/post-content'],
88
+ // inserter: true,
89
+ // content: '<!-- wp:group -->...',
90
+ // filePath: '/path/to/theme/patterns/hero.php',
91
+ // isSynced: false
92
+ // }
93
+ ```
94
+
95
+ ### Parse PHP Header Only
96
+
97
+ Extract metadata from a PHP file's docblock:
98
+
99
+ ```typescript
100
+ import { parsePatternHeader } from '@10up/block-renderer-patterns';
101
+
102
+ const phpContent = `<?php
103
+ /**
104
+ * Title: Hero Section
105
+ * Slug: theme-name/hero
106
+ * Categories: featured, banner
107
+ * Keywords: hero, cta
108
+ * Block Types: core/post-content
109
+ * Viewport Width: 1200
110
+ */
111
+ ?>
112
+ <!-- wp:group -->...`;
113
+
114
+ const metadata = parsePatternHeader(phpContent);
115
+ // {
116
+ // title: 'Hero Section',
117
+ // slug: 'theme-name/hero',
118
+ // categories: ['featured', 'banner'],
119
+ // keywords: ['hero', 'cta'],
120
+ // blockTypes: ['core/post-content'],
121
+ // viewportWidth: 1200
122
+ // }
123
+ ```
124
+
125
+ ### Extract Block Content
126
+
127
+ Get the block markup without the PHP header:
128
+
129
+ ```typescript
130
+ import { extractPatternContent } from '@10up/block-renderer-patterns';
131
+
132
+ const content = extractPatternContent(phpContent);
133
+ // '<!-- wp:group -->...'
134
+ ```
135
+
136
+ ## Querying Patterns
137
+
138
+ ### Get Patterns by Category
139
+
140
+ ```typescript
141
+ import { loadPatterns, getPatternsByCategory } from '@10up/block-renderer-patterns';
142
+
143
+ const registry = loadPatterns('/path/to/theme');
144
+ const featuredPatterns = getPatternsByCategory(registry, 'featured');
145
+ // Returns PatternDefinition[]
146
+ ```
147
+
148
+ ### Get Patterns by Block Type
149
+
150
+ Patterns can be associated with specific block types:
151
+
152
+ ```typescript
153
+ import { getPatternsByBlockType } from '@10up/block-renderer-patterns';
154
+
155
+ // Get patterns for the post content block
156
+ const contentPatterns = getPatternsByBlockType(registry, 'core/post-content');
157
+ ```
158
+
159
+ ### Search Patterns
160
+
161
+ Search across title, description, keywords, and slug:
162
+
163
+ ```typescript
164
+ import { searchPatterns } from '@10up/block-renderer-patterns';
165
+
166
+ const results = searchPatterns(registry, 'hero');
167
+ // Returns patterns matching "hero" in any searchable field
168
+ ```
169
+
170
+ ### Get All Categories
171
+
172
+ ```typescript
173
+ import { getAllCategories } from '@10up/block-renderer-patterns';
174
+
175
+ const categories = getAllCategories(registry);
176
+ // ['banner', 'featured', 'footer', 'header', ...]
177
+ ```
178
+
179
+ ## Types
180
+
181
+ ### PatternDefinition
182
+
183
+ ```typescript
184
+ interface PatternDefinition {
185
+ /** Human-readable title */
186
+ title: string;
187
+ /** Pattern slug, e.g., "theme-name/hero" */
188
+ slug: string;
189
+ /** Pattern categories */
190
+ categories?: string[];
191
+ /** Search keywords */
192
+ keywords?: string[];
193
+ /** Pattern description (for screen readers) */
194
+ description?: string;
195
+ /** Block types this pattern applies to */
196
+ blockTypes?: string[];
197
+ /** Post types where this pattern can be used */
198
+ postTypes?: string[];
199
+ /** Preview iframe width */
200
+ viewportWidth?: number;
201
+ /** Whether to show in inserter (default true) */
202
+ inserter?: boolean;
203
+ /** The actual block markup content */
204
+ content: string;
205
+ /** Source file path */
206
+ filePath: string;
207
+ /** Whether this is a synced pattern (reusable block) */
208
+ isSynced: boolean;
209
+ }
210
+ ```
211
+
212
+ ### PatternRegistry
213
+
214
+ ```typescript
215
+ type PatternRegistry = Map<string, PatternDefinition>;
216
+ ```
217
+
218
+ ### PatternScanResult
219
+
220
+ ```typescript
221
+ interface PatternScanResult {
222
+ /** Successfully parsed patterns */
223
+ patterns: PatternDefinition[];
224
+ /** Files that failed to parse */
225
+ errors: Array<{
226
+ filePath: string;
227
+ error: string;
228
+ }>;
229
+ }
230
+ ```
231
+
232
+ ### PatternMetadata
233
+
234
+ ```typescript
235
+ interface PatternMetadata {
236
+ title?: string;
237
+ slug?: string;
238
+ categories?: string[];
239
+ keywords?: string[];
240
+ description?: string;
241
+ blockTypes?: string[];
242
+ postTypes?: string[];
243
+ viewportWidth?: number;
244
+ inserter?: boolean;
245
+ }
246
+ ```
247
+
248
+ ## Complete Exports
249
+
250
+ ### Functions
251
+
252
+ | Function | Description |
253
+ |----------|-------------|
254
+ | `loadPatterns(themePath)` | Load all patterns and return a registry |
255
+ | `scanPatterns(themePath)` | Scan patterns with error reporting |
256
+ | `createPatternRegistry(scanResult)` | Create registry from scan results |
257
+ | `parsePatternFile(filePath, themeName, isSynced)` | Parse single pattern file |
258
+ | `parsePatternHeader(content)` | Parse PHP header to metadata |
259
+ | `extractPhpCommentHeader(content)` | Extract raw PHP docblock |
260
+ | `extractPatternContent(content)` | Extract block markup from PHP |
261
+ | `getPatternsByCategory(registry, category)` | Filter patterns by category |
262
+ | `getPatternsByBlockType(registry, blockType)` | Filter patterns by block type |
263
+ | `searchPatterns(registry, query)` | Search patterns by keyword |
264
+ | `getAllCategories(registry)` | Get all unique categories |
265
+
266
+ ### Types
267
+
268
+ | Type | Description |
269
+ |------|-------------|
270
+ | `PatternDefinition` | Complete pattern with metadata and content |
271
+ | `PatternRegistry` | Map of slug to pattern definition |
272
+ | `PatternScanResult` | Scan results with patterns and errors |
273
+ | `PatternMetadata` | Metadata extracted from PHP header |
274
+
275
+ ### Zod Schemas
276
+
277
+ | Schema | Description |
278
+ |--------|-------------|
279
+ | `patternMetadataSchema` | Validate pattern metadata objects |
280
+ | `patternDefinitionSchema` | Validate complete pattern definitions |
281
+
282
+ ## License
283
+
284
+ MIT
@@ -0,0 +1,22 @@
1
+ import type { PatternMetadata } from './types.js';
2
+ /**
3
+ * Extracts the PHP comment header from file content.
4
+ * Handles both single-line and multi-line comment formats.
5
+ */
6
+ export declare function extractPhpCommentHeader(content: string): string | null;
7
+ /**
8
+ * Parses PHP file header to extract pattern metadata.
9
+ *
10
+ * Expects PHP files with docblock headers like:
11
+ * - Title: Hero Section
12
+ * - Slug: theme-name/hero
13
+ * - Categories: featured, header
14
+ * - Keywords: hero, banner, cta
15
+ */
16
+ export declare function parsePatternHeader(content: string): PatternMetadata;
17
+ /**
18
+ * Extracts the block content from a PHP pattern file.
19
+ * Content is everything after the PHP closing tag or after the comment block.
20
+ */
21
+ export declare function extractPatternContent(content: string): string;
22
+ //# sourceMappingURL=header-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-parser.d.ts","sourceRoot":"","sources":["../src/header-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA4ClD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAetE;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CA8CnE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7D"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Known PHP header fields for WordPress patterns.
3
+ * @see https://developer.wordpress.org/themes/patterns/registering-patterns/
4
+ */
5
+ const HEADER_FIELDS = {
6
+ 'Title': 'title',
7
+ 'Slug': 'slug',
8
+ 'Categories': 'categories',
9
+ 'Keywords': 'keywords',
10
+ 'Description': 'description',
11
+ 'Block Types': 'blockTypes',
12
+ 'Post Types': 'postTypes',
13
+ 'Viewport Width': 'viewportWidth',
14
+ 'Inserter': 'inserter',
15
+ };
16
+ /**
17
+ * Parses a comma-separated list value from a PHP header.
18
+ */
19
+ function parseListValue(value) {
20
+ return value
21
+ .split(',')
22
+ .map(item => item.trim())
23
+ .filter(item => item.length > 0);
24
+ }
25
+ /**
26
+ * Parses a boolean value from a PHP header.
27
+ */
28
+ function parseBooleanValue(value) {
29
+ const lowered = value.toLowerCase().trim();
30
+ return lowered === 'true' || lowered === 'yes' || lowered === '1';
31
+ }
32
+ /**
33
+ * Parses a number value from a PHP header.
34
+ */
35
+ function parseNumberValue(value) {
36
+ const num = parseInt(value.trim(), 10);
37
+ return isNaN(num) ? undefined : num;
38
+ }
39
+ /**
40
+ * Extracts the PHP comment header from file content.
41
+ * Handles both single-line and multi-line comment formats.
42
+ */
43
+ export function extractPhpCommentHeader(content) {
44
+ // Match PHP opening tag followed by docblock comment
45
+ // Pattern: <?php followed by /** ... */
46
+ const docblockMatch = content.match(/^<\?php\s*\r?\n?\s*\/\*\*([\s\S]*?)\*\//);
47
+ if (docblockMatch) {
48
+ return docblockMatch[1];
49
+ }
50
+ // Also try matching multi-line comment without docblock asterisks
51
+ const multilineMatch = content.match(/^<\?php\s*\r?\n?\s*\/\*([\s\S]*?)\*\//);
52
+ if (multilineMatch) {
53
+ return multilineMatch[1];
54
+ }
55
+ return null;
56
+ }
57
+ /**
58
+ * Parses a single header line to extract field name and value.
59
+ */
60
+ function parseHeaderLine(line) {
61
+ // Remove leading asterisks and whitespace from docblock format
62
+ const cleaned = line.replace(/^\s*\*\s*/, '').trim();
63
+ // Match "Field Name: Value" pattern
64
+ const match = cleaned.match(/^([^:]+):\s*(.+)$/);
65
+ if (!match)
66
+ return null;
67
+ return {
68
+ field: match[1].trim(),
69
+ value: match[2].trim(),
70
+ };
71
+ }
72
+ /**
73
+ * Parses PHP file header to extract pattern metadata.
74
+ *
75
+ * Expects PHP files with docblock headers like:
76
+ * - Title: Hero Section
77
+ * - Slug: theme-name/hero
78
+ * - Categories: featured, header
79
+ * - Keywords: hero, banner, cta
80
+ */
81
+ export function parsePatternHeader(content) {
82
+ const metadata = {};
83
+ // Extract the PHP comment header
84
+ const header = extractPhpCommentHeader(content);
85
+ if (!header) {
86
+ return metadata;
87
+ }
88
+ // Split into lines and parse each
89
+ const lines = header.split('\n');
90
+ for (const line of lines) {
91
+ const parsed = parseHeaderLine(line);
92
+ if (!parsed)
93
+ continue;
94
+ const { field, value } = parsed;
95
+ const metadataKey = HEADER_FIELDS[field];
96
+ if (!metadataKey)
97
+ continue;
98
+ switch (metadataKey) {
99
+ case 'title':
100
+ case 'slug':
101
+ case 'description':
102
+ metadata[metadataKey] = value;
103
+ break;
104
+ case 'categories':
105
+ case 'keywords':
106
+ case 'blockTypes':
107
+ case 'postTypes':
108
+ metadata[metadataKey] = parseListValue(value);
109
+ break;
110
+ case 'viewportWidth':
111
+ metadata[metadataKey] = parseNumberValue(value);
112
+ break;
113
+ case 'inserter':
114
+ metadata[metadataKey] = parseBooleanValue(value);
115
+ break;
116
+ }
117
+ }
118
+ return metadata;
119
+ }
120
+ /**
121
+ * Extracts the block content from a PHP pattern file.
122
+ * Content is everything after the PHP closing tag or after the comment block.
123
+ */
124
+ export function extractPatternContent(content) {
125
+ // Try to find content after PHP closing tag
126
+ const phpCloseMatch = content.match(/\?>\s*([\s\S]*)$/);
127
+ if (phpCloseMatch) {
128
+ return phpCloseMatch[1].trim();
129
+ }
130
+ // If no closing tag, try to extract content after the comment block
131
+ const afterCommentMatch = content.match(/\/\*[\s\S]*?\*\/\s*([\s\S]*)$/);
132
+ if (afterCommentMatch) {
133
+ return afterCommentMatch[1].trim();
134
+ }
135
+ return '';
136
+ }
137
+ //# sourceMappingURL=header-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-parser.js","sourceRoot":"","sources":["../src/header-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type { PatternDefinition, PatternRegistry, PatternScanResult, PatternMetadata, } from './types.js';
2
+ export { patternMetadataSchema, patternDefinitionSchema, } from './types.js';
3
+ export { extractPhpCommentHeader, parsePatternHeader, extractPatternContent, } from './header-parser.js';
4
+ export { parsePatternFile, scanPatterns, createPatternRegistry, loadPatterns, getPatternsByCategory, getPatternsByBlockType, searchPatterns, getAllCategories, } from './scanner.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { patternMetadataSchema, patternDefinitionSchema, } from './types.js';
2
+ // Header parser
3
+ export { extractPhpCommentHeader, parsePatternHeader, extractPatternContent, } from './header-parser.js';
4
+ // Scanner
5
+ export { parsePatternFile, scanPatterns, createPatternRegistry, loadPatterns, getPatternsByCategory, getPatternsByBlockType, searchPatterns, getAllCategories, } from './scanner.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB,gBAAgB;AAChB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,UAAU;AACV,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { PatternDefinition, PatternScanResult, PatternRegistry } from './types.js';
2
+ /**
3
+ * Parses a single pattern file.
4
+ */
5
+ export declare function parsePatternFile(filePath: string, themeName: string, isSynced?: boolean): PatternDefinition;
6
+ /**
7
+ * Scans all pattern directories in a WordPress theme.
8
+ *
9
+ * Scans:
10
+ * - /patterns - Theme patterns
11
+ * - /synced-patterns - Synced (reusable) patterns
12
+ */
13
+ export declare function scanPatterns(themePath: string): PatternScanResult;
14
+ /**
15
+ * Creates a pattern registry from scan results.
16
+ */
17
+ export declare function createPatternRegistry(scanResult: PatternScanResult): PatternRegistry;
18
+ /**
19
+ * Loads patterns from a theme and returns a registry.
20
+ */
21
+ export declare function loadPatterns(themePath: string): PatternRegistry;
22
+ /**
23
+ * Gets patterns by category.
24
+ */
25
+ export declare function getPatternsByCategory(registry: PatternRegistry, category: string): PatternDefinition[];
26
+ /**
27
+ * Gets patterns by block type.
28
+ */
29
+ export declare function getPatternsByBlockType(registry: PatternRegistry, blockType: string): PatternDefinition[];
30
+ /**
31
+ * Searches patterns by keyword.
32
+ */
33
+ export declare function searchPatterns(registry: PatternRegistry, query: string): PatternDefinition[];
34
+ /**
35
+ * Gets all unique categories from the registry.
36
+ */
37
+ export declare function getAllCategories(registry: PatternRegistry): string[];
38
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EAChB,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,OAAe,GACxB,iBAAiB,CA0BnB;AAgDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAoBjE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,iBAAiB,GAAG,eAAe,CAQpF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAG/D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,MAAM,GACf,iBAAiB,EAAE,CAUrB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GAChB,iBAAiB,EAAE,CAUrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,GACZ,iBAAiB,EAAE,CAgBrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,EAAE,CAUpE"}
@@ -0,0 +1,162 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { parsePatternHeader, extractPatternContent } from './header-parser.js';
4
+ /**
5
+ * Parses a single pattern file.
6
+ */
7
+ export function parsePatternFile(filePath, themeName, isSynced = false) {
8
+ const content = fs.readFileSync(filePath, 'utf-8');
9
+ const metadata = parsePatternHeader(content);
10
+ const blockContent = extractPatternContent(content);
11
+ // Generate slug from filename if not specified
12
+ const fileName = path.basename(filePath, '.php');
13
+ const slug = metadata.slug || `${themeName}/${fileName}`;
14
+ // Title is required - use filename as fallback
15
+ const title = metadata.title || fileName.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
16
+ return {
17
+ title,
18
+ slug,
19
+ categories: metadata.categories,
20
+ keywords: metadata.keywords,
21
+ description: metadata.description,
22
+ blockTypes: metadata.blockTypes,
23
+ postTypes: metadata.postTypes,
24
+ viewportWidth: metadata.viewportWidth,
25
+ inserter: metadata.inserter,
26
+ content: blockContent,
27
+ filePath,
28
+ isSynced,
29
+ };
30
+ }
31
+ /**
32
+ * Scans a directory for pattern files.
33
+ */
34
+ function scanDirectory(dirPath, themeName, isSynced) {
35
+ const result = {
36
+ patterns: [],
37
+ errors: [],
38
+ };
39
+ if (!fs.existsSync(dirPath)) {
40
+ return result;
41
+ }
42
+ const files = fs.readdirSync(dirPath);
43
+ for (const file of files) {
44
+ if (!file.endsWith('.php'))
45
+ continue;
46
+ const filePath = path.join(dirPath, file);
47
+ try {
48
+ const pattern = parsePatternFile(filePath, themeName, isSynced);
49
+ result.patterns.push(pattern);
50
+ }
51
+ catch (error) {
52
+ result.errors.push({
53
+ filePath,
54
+ error: error instanceof Error ? error.message : String(error),
55
+ });
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+ /**
61
+ * Gets the theme name from the theme directory.
62
+ * Uses the directory name as the theme name.
63
+ */
64
+ function getThemeName(themePath) {
65
+ return path.basename(themePath);
66
+ }
67
+ /**
68
+ * Scans all pattern directories in a WordPress theme.
69
+ *
70
+ * Scans:
71
+ * - /patterns - Theme patterns
72
+ * - /synced-patterns - Synced (reusable) patterns
73
+ */
74
+ export function scanPatterns(themePath) {
75
+ const themeName = getThemeName(themePath);
76
+ const result = {
77
+ patterns: [],
78
+ errors: [],
79
+ };
80
+ // Scan main patterns directory
81
+ const patternsDir = path.join(themePath, 'patterns');
82
+ const patternsResult = scanDirectory(patternsDir, themeName, false);
83
+ result.patterns.push(...patternsResult.patterns);
84
+ result.errors.push(...patternsResult.errors);
85
+ // Scan synced patterns directory
86
+ const syncedPatternsDir = path.join(themePath, 'synced-patterns');
87
+ const syncedResult = scanDirectory(syncedPatternsDir, themeName, true);
88
+ result.patterns.push(...syncedResult.patterns);
89
+ result.errors.push(...syncedResult.errors);
90
+ return result;
91
+ }
92
+ /**
93
+ * Creates a pattern registry from scan results.
94
+ */
95
+ export function createPatternRegistry(scanResult) {
96
+ const registry = new Map();
97
+ for (const pattern of scanResult.patterns) {
98
+ registry.set(pattern.slug, pattern);
99
+ }
100
+ return registry;
101
+ }
102
+ /**
103
+ * Loads patterns from a theme and returns a registry.
104
+ */
105
+ export function loadPatterns(themePath) {
106
+ const scanResult = scanPatterns(themePath);
107
+ return createPatternRegistry(scanResult);
108
+ }
109
+ /**
110
+ * Gets patterns by category.
111
+ */
112
+ export function getPatternsByCategory(registry, category) {
113
+ const patterns = [];
114
+ for (const pattern of registry.values()) {
115
+ if (pattern.categories?.includes(category)) {
116
+ patterns.push(pattern);
117
+ }
118
+ }
119
+ return patterns;
120
+ }
121
+ /**
122
+ * Gets patterns by block type.
123
+ */
124
+ export function getPatternsByBlockType(registry, blockType) {
125
+ const patterns = [];
126
+ for (const pattern of registry.values()) {
127
+ if (pattern.blockTypes?.includes(blockType)) {
128
+ patterns.push(pattern);
129
+ }
130
+ }
131
+ return patterns;
132
+ }
133
+ /**
134
+ * Searches patterns by keyword.
135
+ */
136
+ export function searchPatterns(registry, query) {
137
+ const loweredQuery = query.toLowerCase();
138
+ const patterns = [];
139
+ for (const pattern of registry.values()) {
140
+ const matchesTitle = pattern.title.toLowerCase().includes(loweredQuery);
141
+ const matchesDescription = pattern.description?.toLowerCase().includes(loweredQuery);
142
+ const matchesKeywords = pattern.keywords?.some(k => k.toLowerCase().includes(loweredQuery));
143
+ const matchesSlug = pattern.slug.toLowerCase().includes(loweredQuery);
144
+ if (matchesTitle || matchesDescription || matchesKeywords || matchesSlug) {
145
+ patterns.push(pattern);
146
+ }
147
+ }
148
+ return patterns;
149
+ }
150
+ /**
151
+ * Gets all unique categories from the registry.
152
+ */
153
+ export function getAllCategories(registry) {
154
+ const categories = new Set();
155
+ for (const pattern of registry.values()) {
156
+ for (const category of pattern.categories || []) {
157
+ categories.add(category);
158
+ }
159
+ }
160
+ return Array.from(categories).sort();
161
+ }
162
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Pattern definition extracted from a PHP pattern file.
4
+ * @see https://developer.wordpress.org/themes/patterns/registering-patterns/
5
+ */
6
+ export interface PatternDefinition {
7
+ /** Human-readable title */
8
+ title: string;
9
+ /** Pattern slug, e.g., "theme-name/hero" */
10
+ slug: string;
11
+ /** Pattern categories */
12
+ categories?: string[];
13
+ /** Search keywords */
14
+ keywords?: string[];
15
+ /** Pattern description (for screen readers) */
16
+ description?: string;
17
+ /** Block types this pattern applies to */
18
+ blockTypes?: string[];
19
+ /** Post types where this pattern can be used */
20
+ postTypes?: string[];
21
+ /** Preview iframe width */
22
+ viewportWidth?: number;
23
+ /** Whether to show in inserter (default true) */
24
+ inserter?: boolean;
25
+ /** The actual block markup content */
26
+ content: string;
27
+ /** Source file path */
28
+ filePath: string;
29
+ /** Whether this is a synced pattern (reusable block) */
30
+ isSynced: boolean;
31
+ }
32
+ /**
33
+ * Registry of all patterns in a theme
34
+ */
35
+ export type PatternRegistry = Map<string, PatternDefinition>;
36
+ /**
37
+ * Result of scanning patterns
38
+ */
39
+ export interface PatternScanResult {
40
+ /** Successfully parsed patterns */
41
+ patterns: PatternDefinition[];
42
+ /** Files that failed to parse */
43
+ errors: Array<{
44
+ filePath: string;
45
+ error: string;
46
+ }>;
47
+ }
48
+ /**
49
+ * Metadata extracted from PHP file header
50
+ */
51
+ export interface PatternMetadata {
52
+ title?: string;
53
+ slug?: string;
54
+ categories?: string[];
55
+ keywords?: string[];
56
+ description?: string;
57
+ blockTypes?: string[];
58
+ postTypes?: string[];
59
+ viewportWidth?: number;
60
+ inserter?: boolean;
61
+ }
62
+ export declare const patternMetadataSchema: z.ZodObject<{
63
+ title: z.ZodOptional<z.ZodString>;
64
+ slug: z.ZodOptional<z.ZodString>;
65
+ categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
66
+ keywords: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
67
+ description: z.ZodOptional<z.ZodString>;
68
+ blockTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
69
+ postTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
70
+ viewportWidth: z.ZodOptional<z.ZodNumber>;
71
+ inserter: z.ZodOptional<z.ZodBoolean>;
72
+ }, "strip", z.ZodTypeAny, {
73
+ title?: string | undefined;
74
+ slug?: string | undefined;
75
+ categories?: string[] | undefined;
76
+ keywords?: string[] | undefined;
77
+ description?: string | undefined;
78
+ blockTypes?: string[] | undefined;
79
+ postTypes?: string[] | undefined;
80
+ viewportWidth?: number | undefined;
81
+ inserter?: boolean | undefined;
82
+ }, {
83
+ title?: string | undefined;
84
+ slug?: string | undefined;
85
+ categories?: string[] | undefined;
86
+ keywords?: string[] | undefined;
87
+ description?: string | undefined;
88
+ blockTypes?: string[] | undefined;
89
+ postTypes?: string[] | undefined;
90
+ viewportWidth?: number | undefined;
91
+ inserter?: boolean | undefined;
92
+ }>;
93
+ export declare const patternDefinitionSchema: z.ZodObject<{
94
+ title: z.ZodString;
95
+ slug: z.ZodString;
96
+ categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
97
+ keywords: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
98
+ description: z.ZodOptional<z.ZodString>;
99
+ blockTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
100
+ postTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
101
+ viewportWidth: z.ZodOptional<z.ZodNumber>;
102
+ inserter: z.ZodOptional<z.ZodBoolean>;
103
+ content: z.ZodString;
104
+ filePath: z.ZodString;
105
+ isSynced: z.ZodBoolean;
106
+ }, "strip", z.ZodTypeAny, {
107
+ title: string;
108
+ slug: string;
109
+ content: string;
110
+ filePath: string;
111
+ isSynced: boolean;
112
+ categories?: string[] | undefined;
113
+ keywords?: string[] | undefined;
114
+ description?: string | undefined;
115
+ blockTypes?: string[] | undefined;
116
+ postTypes?: string[] | undefined;
117
+ viewportWidth?: number | undefined;
118
+ inserter?: boolean | undefined;
119
+ }, {
120
+ title: string;
121
+ slug: string;
122
+ content: string;
123
+ filePath: string;
124
+ isSynced: boolean;
125
+ categories?: string[] | undefined;
126
+ keywords?: string[] | undefined;
127
+ description?: string | undefined;
128
+ blockTypes?: string[] | undefined;
129
+ postTypes?: string[] | undefined;
130
+ viewportWidth?: number | undefined;
131
+ inserter?: boolean | undefined;
132
+ }>;
133
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,2BAA2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,iCAAiC;IACjC,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUhC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAalC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ // Zod schema for pattern metadata validation
3
+ export const patternMetadataSchema = z.object({
4
+ title: z.string().optional(),
5
+ slug: z.string().optional(),
6
+ categories: z.array(z.string()).optional(),
7
+ keywords: z.array(z.string()).optional(),
8
+ description: z.string().optional(),
9
+ blockTypes: z.array(z.string()).optional(),
10
+ postTypes: z.array(z.string()).optional(),
11
+ viewportWidth: z.number().optional(),
12
+ inserter: z.boolean().optional(),
13
+ });
14
+ export const patternDefinitionSchema = z.object({
15
+ title: z.string(),
16
+ slug: z.string(),
17
+ categories: z.array(z.string()).optional(),
18
+ keywords: z.array(z.string()).optional(),
19
+ description: z.string().optional(),
20
+ blockTypes: z.array(z.string()).optional(),
21
+ postTypes: z.array(z.string()).optional(),
22
+ viewportWidth: z.number().optional(),
23
+ inserter: z.boolean().optional(),
24
+ content: z.string(),
25
+ filePath: z.string(),
26
+ isSynced: z.boolean(),
27
+ });
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkExB,6CAA6C;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACzC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACzC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;CACtB,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@10up/block-renderer-patterns",
3
+ "version": "0.1.4",
4
+ "description": "Pattern directory scanner and PHP header parser for WordPress block patterns",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "zod": "^3.24.0",
20
+ "@10up/block-renderer-core": "0.1.4"
21
+ },
22
+ "devDependencies": {
23
+ "typescript": "^5.7.0",
24
+ "vitest": "^2.1.0"
25
+ },
26
+ "keywords": [
27
+ "wordpress",
28
+ "blocks",
29
+ "patterns",
30
+ "gutenberg"
31
+ ],
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/10up/json-block-renderer",
36
+ "directory": "packages/patterns"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.build.json",
43
+ "dev": "tsc -p tsconfig.build.json --watch",
44
+ "typecheck": "tsc --noEmit",
45
+ "clean": "rm -rf dist",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest"
48
+ }
49
+ }