@stellisoft/stellify-mcp 0.1.37 → 0.1.38

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/dist/index.js CHANGED
@@ -1509,7 +1509,7 @@ const SERVER_INSTRUCTIONS = `Stellify is a coding platform where code is stored
1509
1509
  // Create MCP server
1510
1510
  const server = new Server({
1511
1511
  name: 'stellify-mcp',
1512
- version: '0.1.37',
1512
+ version: '0.1.38',
1513
1513
  }, {
1514
1514
  capabilities: {
1515
1515
  tools: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellisoft/stellify-mcp",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "mcpName": "io.github.MattStellisoft/stellify-mcp",
5
5
  "description": "MCP server for Stellify - AI-native code generation platform",
6
6
  "main": "dist/index.js",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/Stellify-Software-Ltd/stellify-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.1.37",
9
+ "version": "0.1.38",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@stellisoft/stellify-mcp",
14
- "version": "0.1.37",
14
+ "version": "0.1.38",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -1,264 +1,317 @@
1
1
  ---
2
2
  name: wordpress-import
3
- description: "Use this skill when importing WordPress sites into Stellify. Invoke with /wordpress-import to start the guided workflow. Covers: analyzing WordPress exports, converting post types to Eloquent models, transforming PHP templates to Vue components, migrating forms and plugins, and creating routes and API endpoints."
3
+ description: "Use this skill when importing WordPress sites into Stellify. Invoke with /wordpress-import to analyse a WordPress project and generate resources for custom post types, taxonomies, and fields. Assumes standard WordPress models (Post, Page, Category, Tag, User, Media) are already scaffolded via Stellify."
4
4
  license: MIT
5
+ icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>wordpress</title><path d="M3.42,12C3.42,10.76 3.69,9.58 4.16,8.5L8.26,19.72C5.39,18.33 3.42,15.4 3.42,12M17.79,11.57C17.79,12.3 17.5,13.15 17.14,14.34L16.28,17.2L13.18,8L14.16,7.9C14.63,7.84 14.57,7.16 14.11,7.19C14.11,7.19 12.72,7.3 11.82,7.3L9.56,7.19C9.1,7.16 9.05,7.87 9.5,7.9L10.41,8L11.75,11.64L9.87,17.27L6.74,8L7.73,7.9C8.19,7.84 8.13,7.16 7.67,7.19C7.67,7.19 6.28,7.3 5.38,7.3L4.83,7.29C6.37,4.96 9,3.42 12,3.42C14.23,3.42 16.27,4.28 17.79,5.67H17.68C16.84,5.67 16.24,6.4 16.24,7.19C16.24,7.9 16.65,8.5 17.08,9.2C17.41,9.77 17.79,10.5 17.79,11.57M12.15,12.75L14.79,19.97L14.85,20.09C13.96,20.41 13,20.58 12,20.58C11.16,20.58 10.35,20.46 9.58,20.23L12.15,12.75M19.53,7.88C20.2,9.11 20.58,10.5 20.58,12C20.58,15.16 18.86,17.93 16.31,19.41L18.93,11.84C19.42,10.62 19.59,9.64 19.59,8.77L19.53,7.88M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,21.54C17.26,21.54 21.54,17.26 21.54,12C21.54,6.74 17.26,2.46 12,2.46C6.74,2.46 2.46,6.74 2.46,12C2.46,17.26 6.74,21.54 12,21.54Z" /></svg>
5
6
  metadata:
6
7
  author: stellify
7
8
  ---
8
9
 
9
10
  # WordPress Import Skill
10
11
 
11
- You are importing a WordPress site into Stellify by reading its PHP theme files and recreating the site as a structured Laravel application using the Stellify MCP tools.
12
+ You are importing a WordPress site into Stellify. This skill focuses on **analysing what's custom** about the WordPress site and generating only those elements. Standard WordPress functionality (Posts, Pages, Categories, Tags, Users, Media) is handled by Stellify's WordPress scaffold.
12
13
 
13
- **Match the rendering approach of the WordPress site.** If content is server-rendered in WordPress (which most of it will be posts, pages, archives, navigation), create Blade templates. If a feature uses JavaScript for client-side interactivity (AJAX forms, dynamic filtering, live search, infinite scroll, modals, sliders), create a Vue component for that specific piece. The default is Blade — only reach for Vue when the WordPress source is doing something that genuinely requires JS.
14
+ ## Step 1Verify WordPress Scaffold
14
15
 
15
- ## Step 1 Identify the Active Theme
16
+ Before proceeding, check that the Stellify WordPress scaffold has been run. Look for the presence of standard WordPress models in the Laravel project:
16
17
 
17
- Look in `./wp-content/themes/` to find the active theme. If there are multiple themes, check for the most recently modified one, or the one with the most template files. If unsure, ask which theme to import.
18
+ - `app/Models/Post.php`
19
+ - `app/Models/Page.php`
20
+ - `app/Models/Category.php`
21
+ - `app/Models/Tag.php`
18
22
 
19
- Before proceeding, ask the user:
23
+ If these don't exist, instruct the user:
20
24
 
21
- > **How do you want to handle the database?**
25
+ > **WordPress scaffold required**
22
26
  >
23
- > **A) Connect to existing WordPress database** Models map directly to the WordPress tables (`wp_posts`, `wp_users`, etc.) using the existing column names. No migrations, no data copying. Your Laravel app reads and writes to the same database WordPress uses. This is the fastest path.
27
+ > Before importing, you need to run the Stellify WordPress scaffold. This creates the standard models, controllers, and routes that every WordPress site uses.
24
28
  >
25
- > **B) Fresh database** — Create new Laravel migrations with clean column names (`title` instead of `post_title`, etc.). You start with an empty database and can optionally migrate content from WordPress later.
26
-
27
- These are the only questions you may ask. Do not ask anything else.
29
+ > Run: `[scaffold command TBD]`
30
+ >
31
+ > Let me know when this is complete.
28
32
 
29
- ## Step 2 Inventory the Theme
33
+ Do not proceed until the scaffold is in place.
30
34
 
31
- Read the full theme directory. Categorise every file:
35
+ ## Step 2 Analyse the WordPress Project
32
36
 
33
- - **Core templates**: index.php, single.php, page.php, archive.php, search.php, 404.php, front-page.php, home.php
34
- - **Structural partials**: header.php, footer.php, sidebar.php
35
- - **Template parts**: anything in template-parts/ or patterns/
36
- - **Functions**: functions.php (and any files it includes/requires)
37
- - **Styles**: style.css, any CSS/SCSS files
38
- - **Config**: theme.json if present (block theme configuration)
37
+ Perform a comprehensive analysis of the WordPress site to understand what's custom. This produces a report before any code generation happens.
39
38
 
40
- Print the inventory before proceeding.
39
+ ### 2a. Identify the Active Theme
41
40
 
42
- ## Step 3 Analyse functions.php
41
+ Look in `./wp-content/themes/` to find the active theme. If there are multiple themes, check for the most recently modified one, or the one with the most template files. If unsure, ask which theme to import.
43
42
 
44
- Read functions.php thoroughly. Extract:
43
+ Note whether it's a classic PHP theme or a block theme (presence of `theme.json` and HTML templates).
44
+
45
+ ### 2b. Scan for Custom Post Types & Taxonomies
46
+
47
+ Read `functions.php` and any files it includes/requires. Extract:
48
+
49
+ - **Custom post types** via `register_post_type()` — capture name, labels, supports array, and any custom rewrite rules
50
+ - **Custom taxonomies** via `register_taxonomy()` — capture name, which post types it attaches to, hierarchical setting
51
+
52
+ Also check for CPT plugins that store configuration differently:
53
+ - Custom Post Type UI stores config in `wp_options` under `cptui_post_types` and `cptui_taxonomies`
54
+ - Pods, Toolset, and similar plugins have their own storage patterns
55
+
56
+ ### 2c. Scan Plugins Directory
57
+
58
+ List the contents of `wp-content/plugins/` and categorise:
59
+
60
+ **Functionality plugins** (affect what the site does — need attention):
61
+ - WooCommerce — e-commerce (major rebuild)
62
+ - Advanced Custom Fields / ACF Pro — custom fields
63
+ - Gravity Forms / Contact Form 7 / WPForms — forms
64
+ - The Events Calendar — event post type
65
+ - Custom plugin folders (not from wordpress.org)
66
+
67
+ **Low priority** (usually don't need porting):
68
+ - Yoast SEO / Rank Math — SEO meta (can note fields but not critical)
69
+ - Caching plugins (W3 Total Cache, WP Rocket)
70
+ - Security plugins (Wordfence, Sucuri)
71
+ - Backup plugins
72
+
73
+ **Builder plugins** (affect how templates work):
74
+ - Elementor / Elementor Pro
75
+ - WPBakery / Visual Composer
76
+ - Divi Builder
77
+ - Beaver Builder
78
+
79
+ Note: If a builder plugin is present, templates may be stored in the database rather than theme files.
80
+
81
+ ### 2d. Database Analysis
82
+
83
+ If database access is available (direct connection or SQL dump), run these diagnostic queries:
84
+
85
+ ```sql
86
+ -- Custom post types in use (beyond standard post/page/attachment)
87
+ SELECT post_type, COUNT(*) as count
88
+ FROM wp_posts
89
+ WHERE post_status = 'publish'
90
+ AND post_type NOT IN ('post', 'page', 'attachment', 'revision', 'nav_menu_item', 'wp_template', 'wp_template_part', 'wp_global_styles', 'wp_navigation')
91
+ GROUP BY post_type
92
+ ORDER BY count DESC;
93
+
94
+ -- Custom taxonomies in use (beyond standard category/post_tag)
95
+ SELECT taxonomy, COUNT(*) as term_count
96
+ FROM wp_term_taxonomy
97
+ WHERE taxonomy NOT IN ('category', 'post_tag', 'nav_menu', 'link_category', 'post_format', 'wp_theme', 'wp_template_part_area')
98
+ GROUP BY taxonomy
99
+ ORDER BY term_count DESC;
100
+
101
+ -- Custom meta keys (reveals ACF fields, custom meta)
102
+ -- Excludes WordPress internal keys (prefixed with _)
103
+ SELECT meta_key, COUNT(*) as usage_count
104
+ FROM wp_postmeta
105
+ WHERE meta_key NOT LIKE '\_%'
106
+ GROUP BY meta_key
107
+ ORDER BY usage_count DESC
108
+ LIMIT 30;
109
+
110
+ -- ACF field groups (if ACF is used)
111
+ SELECT post_title, post_name
112
+ FROM wp_posts
113
+ WHERE post_type = 'acf-field-group'
114
+ AND post_status = 'publish';
115
+
116
+ -- Shortcodes in content (indicates embedded functionality)
117
+ SELECT post_type, COUNT(*) as posts_with_shortcodes
118
+ FROM wp_posts
119
+ WHERE post_content REGEXP '\\[[a-zA-Z0-9_-]+.*\\]'
120
+ AND post_status = 'publish'
121
+ GROUP BY post_type;
122
+
123
+ -- Gutenberg blocks in use (for block themes)
124
+ SELECT
125
+ SUBSTRING_INDEX(SUBSTRING_INDEX(post_content, '<!-- wp:', -1), ' ', 1) as block_type,
126
+ COUNT(*) as usage_count
127
+ FROM wp_posts
128
+ WHERE post_content LIKE '%<!-- wp:%'
129
+ AND post_status = 'publish'
130
+ GROUP BY block_type
131
+ ORDER BY usage_count DESC
132
+ LIMIT 20;
133
+ ```
45
134
 
46
- - **Custom post types** registered via `register_post_type()` → these become Laravel models
47
- - **Taxonomies** registered via `register_taxonomy()` → these become models or enums
48
- - **Navigation menus** registered via `register_nav_menus()` → these define nav structure
49
- - **Widget areas** registered via `register_sidebar()` → note for layout
50
- - **Enqueued scripts/styles** via `wp_enqueue_script/style()` → note any JS dependencies
51
- - **Custom image sizes** via `add_image_size()` → note for media handling
52
- - **Theme supports** via `add_theme_support()` → note post formats, thumbnails, etc.
53
- - **Shortcodes** via `add_shortcode()` → these become Blade includes or components
54
- - **AJAX handlers** via `wp_ajax_*` → these become API routes
55
- - **Any included files** → read those too
135
+ ### 2e. Produce Analysis Report
56
136
 
57
- ## Step 4 Plan the Laravel Structure
137
+ Present a structured summary before proceeding:
58
138
 
59
- Before calling any Stellify tools, plan:
139
+ ```
140
+ ## WordPress Site Analysis
141
+
142
+ ### Theme
143
+ - Name: theme-name
144
+ - Type: Classic PHP / Block theme
145
+ - Template files: [count]
146
+
147
+ ### Content Summary
148
+ - Posts: [count]
149
+ - Pages: [count]
150
+ - [custom-type]: [count]
151
+
152
+ ### Custom Post Types
153
+ | Name | Slug | Supports | Count |
154
+ |------|------|----------|-------|
155
+ | Portfolio | project | title, editor, thumbnail | 34 |
156
+ | Testimonial | testimonial | title, editor | 12 |
157
+
158
+ ### Custom Taxonomies
159
+ | Name | Slug | Attached To | Hierarchical | Terms |
160
+ |------|------|-------------|--------------|-------|
161
+ | Project Type | project_type | project | Yes | 5 |
162
+
163
+ ### Custom Fields (non-standard meta keys)
164
+ | Key | Used By | Count |
165
+ |-----|---------|-------|
166
+ | project_client | project | 34 |
167
+ | project_url | project | 34 |
168
+ | testimonial_company | testimonial | 12 |
169
+
170
+ ### Plugins Requiring Attention
171
+ - Advanced Custom Fields Pro — field definitions above
172
+ - Contact Form 7 — 2 forms found
173
+
174
+ ### Content Flags
175
+ - 15 posts contain shortcodes (will need processing during content migration)
176
+ - Page builder detected: Elementor (some layouts stored in database)
177
+
178
+ ### Generation Plan
179
+ **Will generate:**
180
+ - Model: Project (custom post type)
181
+ - Model: Testimonial (custom post type)
182
+ - Model: ProjectType (custom taxonomy)
183
+ - Add fields to models: client, url, company
184
+
185
+ **Standard (already scaffolded):**
186
+ - Post, Page, Category, Tag, User, Media
187
+
188
+ **Manual attention needed:**
189
+ - Contact forms (2) — recreate in Laravel
190
+ - Shortcodes in content — process during migration
191
+ - Elementor layouts — extract design intent from theme templates
192
+ ```
60
193
 
61
- - **Models:** One per post type (Post, Page, plus any custom types from Step 3)
62
- - **Controllers:** One per model with index/show actions
63
- - **Routes:** Match WordPress URL structure (archive at `/`, singles at `/{slug}`, taxonomies at `/category/{slug}`)
64
- - **Views:** Mirror WordPress template hierarchy — layout from header+footer, index/show views per post type, partials from template-parts
65
- - **Migrations (Mode B only):** One per model with fields from WordPress core + any custom fields found in templates
194
+ After presenting the report, ask:
66
195
 
67
- ## Step 5 Build in Stellify (Order of Operations)
196
+ > Does this analysis look correct? Ready to proceed with generating the custom resources?
68
197
 
69
- Execute the plan using Stellify MCP tools in this order. This order matters parent records must exist before children.
198
+ ## Step 3Generate Custom Resources
70
199
 
71
- ### 5a. Create Models, Migrations & Controllers
200
+ For each custom post type and taxonomy identified, create the necessary Laravel resources using Stellify MCP tools.
72
201
 
73
- Use the `create_resources` tool with `api: false` to generate models and controllers together. The `api: false` flag ensures controller methods return data arrays (for Blade views) rather than JSON responses.
202
+ ### 3a. Custom Post Type Models
74
203
 
75
- **Route Model Binding with Slugs:** WordPress URLs use slugs (e.g., `/post/my-article-title`). After creating each model with a `slug` field, add a `getRouteKeyName()` method so Laravel's route model binding works correctly:
204
+ For each custom post type, use `create_resources` with `api: false`:
76
205
 
77
- ```php
78
- public function getRouteKeyName(): string
79
- {
80
- return 'slug';
81
- }
82
- ```
206
+ **Model requirements:**
207
+ - Table name matching the post type slug (e.g., `projects`, `testimonials`)
208
+ - Standard fields: `title`, `slug`, `content`, `excerpt`, `status`, `published_at`, `author_id`
209
+ - Custom fields identified from meta analysis
210
+ - `getRouteKeyName()` returning `'slug'` for URL-friendly routing
211
+ - Relationships to custom taxonomies
83
212
 
84
- Add this method to **Post**, **Category**, **Tag**, and any custom post type models that use slugs in their URLs. Without this, routes like `/post/{post}` will try to look up by ID instead of slug, causing 404 errors.
213
+ **Migration requirements:**
214
+ - All standard fields plus custom fields
215
+ - Foreign keys to users table for author
216
+ - Indexes on slug, status, published_at
85
217
 
86
- **If Mode A (connect to existing WordPress database):**
218
+ **Controller requirements:**
219
+ - `index()` returning paginated published items
220
+ - `show($model)` returning single item
221
+ - Return arrays (Stellify convention), not views or JSON
87
222
 
88
- Create resources that map to the existing WordPress tables. No migrations. Set the model's table and primary key to match WordPress.
223
+ Example model structure:
89
224
 
90
225
  ```php
91
- // Example Post model
92
- class Post extends Model {
93
- protected $table = 'wp_posts';
94
- protected $primaryKey = 'ID';
226
+ class Project extends Model
227
+ {
228
+ protected $fillable = [
229
+ 'title', 'slug', 'content', 'excerpt',
230
+ 'status', 'published_at', 'author_id',
231
+ 'client', 'url', // custom fields
232
+ ];
233
+
234
+ protected $casts = [
235
+ 'published_at' => 'datetime',
236
+ ];
95
237
 
96
- // Enable slug-based route model binding (WordPress uses post_name for slugs)
97
238
  public function getRouteKeyName(): string
98
239
  {
99
- return 'post_name';
240
+ return 'slug';
100
241
  }
101
242
 
102
- // Scope to only published posts (not revisions, drafts, etc.)
103
- public function scopePublished($query) {
104
- return $query->where('post_status', 'publish')
105
- ->where('post_type', 'post');
243
+ public function author(): BelongsTo
244
+ {
245
+ return $this->belongsTo(User::class, 'author_id');
106
246
  }
107
- }
108
- ```
109
-
110
- Key WordPress table mappings:
111
- - Posts & Pages → `wp_posts` (distinguished by `post_type` column: 'post', 'page', or custom types)
112
- - Categories & Tags → `wp_terms` + `wp_term_taxonomy` + `wp_term_relationships`
113
- - Users → `wp_users`
114
- - Post meta / custom fields → `wp_postmeta`
115
- - Comments → `wp_comments`
116
- - Navigation menus → `wp_posts` with `post_type = 'nav_menu_item'` + `wp_terms` with taxonomy `nav_menu`
117
-
118
- In Blade templates, use WordPress column names:
119
- - `$post->post_title` (not `$post->title`)
120
- - `$post->post_content` (not `$post->content`)
121
- - `$post->post_excerpt` (not `$post->excerpt`)
122
- - `$post->post_name` (this is the slug)
123
- - `$post->post_date` (not `$post->published_at`)
124
- - `$post->post_status` (not `$post->status`)
125
-
126
- **If Mode B (fresh database):**
127
-
128
- Create new resources with clean Laravel migrations for each model identified in Step 4. Use clean column names (`title`, `slug`, `content`, `excerpt`, `status`, `published_at`, etc.). After the import is complete, suggest a data migration SQL query or artisan command that maps data from the WordPress tables to the new schema.
129
-
130
- For each model with a `slug` field, add `getRouteKeyName()`:
131
-
132
- ```php
133
- public function getRouteKeyName(): string
134
- {
135
- return 'slug';
136
- }
137
- ```
138
-
139
- ### 5b. Refine Controller Methods
140
247
 
141
- `create_resources` (Step 5a) scaffolds controllers automatically. Review and refine the generated methods to ensure they query the right data. Controller methods in Stellify return data arrays — Stellify automatically merges these into the Blade view context. For example:
142
-
143
- ```php
144
- // CORRECT for Stellify — returns a data array, Stellify handles the view binding
145
- public function index(): array
146
- {
147
- return ['posts' => Post::where('status', 'published')->latest('published_at')->paginate(10)];
148
- }
149
-
150
- public function show(Post $post): array
151
- {
152
- return ['post' => $post];
153
- }
154
-
155
- // WRONG — do not return JSON
156
- public function index()
157
- {
158
- return Post::where('status', 'published')->get();
159
- }
248
+ public function projectTypes(): BelongsToMany
249
+ {
250
+ return $this->belongsToMany(ProjectType::class);
251
+ }
160
252
 
161
- // WRONG — do not call view() directly, Stellify handles this
162
- public function index()
163
- {
164
- return view('posts.index', compact('posts'));
253
+ public function scopePublished($query)
254
+ {
255
+ return $query->where('status', 'published');
256
+ }
165
257
  }
166
258
  ```
167
259
 
168
- **Mode A note:** WordPress stores posts, pages, and custom post types all in `wp_posts`, distinguished by the `post_type` column. Controllers must scope queries accordingly — e.g. `Post::where('post_type', 'post')->where('post_status', 'publish')`. It also stores revisions and auto-drafts in the same table, so always filter by `post_status`.
169
-
170
- ### 5c. Create Routes
171
- Create route entries mapping URLs to controller methods.
172
-
173
- ### 5d. Create the Layout (layouts/app.blade.php)
174
- Read header.php and footer.php. Create a single Blade layout that combines:
175
- - The HTML structure from header.php (doctype, head, opening body, nav)
176
- - `@yield('content')` for page content
177
- - The structure from footer.php (closing elements, footer content)
178
-
179
- Translate WordPress functions to Blade:
180
- - `wp_head()` → `@vite(['resources/css/app.css', 'resources/js/app.js'])` and `<meta>` tags
181
- - `wp_footer()` → nothing needed (Vite handles it)
182
- - `wp_nav_menu()` → `@include('partials.nav')`
183
- - `bloginfo('name')` → `{{ config('app.name') }}`
184
- - `bloginfo('description')` → `{{ config('app.description', '') }}`
185
- - `body_class()` → appropriate Tailwind classes
186
- - `language_attributes()` → `lang="{{ str_replace('_', '-', app()->getLocale()) }}"`
187
-
188
- ### 5e. Create Blade Views
189
- For each WordPress template file, read the PHP and create the equivalent Blade view using `html_to_elements`. **All views use `@extends('layouts.app')` and `@section('content')`.**
190
-
191
- **⚠️ Multiple Root Elements:** When converting HTML with multiple root-level elements (e.g., `<header>`, `<main>`, `<footer>`), only the first root element gets attached to the route. Make separate `html_to_elements` calls for each root element.
260
+ ### 3b. Custom Taxonomy Models
192
261
 
193
- **WordPress Blade translation guide:**
262
+ For each custom taxonomy:
194
263
 
195
- Mode A uses WordPress column names; Mode B uses clean Laravel names.
264
+ **Model requirements:**
265
+ - Table name matching taxonomy slug (e.g., `project_types`)
266
+ - Fields: `name`, `slug`, `description`, `parent_id` (if hierarchical)
267
+ - `getRouteKeyName()` returning `'slug'`
268
+ - Relationship to associated post types via pivot table
196
269
 
197
- **IMPORTANT:** Inside `@foreach` loops, use `$item` as the loop variable. This matches the Stellify assembler's expectations for `textField`, `hrefField`, `srcField` attributes.
270
+ **Migration requirements:**
271
+ - Main taxonomy table
272
+ - Pivot table linking to each associated post type (e.g., `project_project_type`)
198
273
 
199
- | WordPress | Blade (Mode A) | Blade (Mode B) | Stellify Attribute |
200
- |-----------|----------------|----------------|-------------------|
201
- | `the_title()` | `{{ $item->post_title }}` | `{{ $item->title }}` | `textField: "title"` |
202
- | `the_content()` | `{!! $item->post_content !!}` | `{!! $item->content !!}` | statement with code |
203
- | `the_excerpt()` | `{{ $item->post_excerpt }}` | `{{ $item->excerpt }}` | `textField: "excerpt"` |
204
- | `the_permalink()` | `{{ route('posts.show', $item->post_name) }}` | `{{ route('posts.show', $item->slug) }}` | `hrefExpression: "..."` |
205
- | `the_date()` | `{{ $item->post_date->format('d M Y') }}` | `{{ $item->published_at->format('d M Y') }}` | statement with code |
206
- | `the_author()` | `{{ $item->author->display_name }}` | `{{ $item->author->name }}` | statement with code |
207
- | `get_template_part()` | `@include('partials.post-card', ['post' => $item])` | same | s-directive |
208
- | `have_posts()` | `@foreach($posts as $item)` | same | s-directive pair |
274
+ ### 3c. Routes
209
275
 
210
- **Conditional Rendering with `s-directive`:**
276
+ Create routes following WordPress URL conventions where sensible:
211
277
 
212
- WordPress blocks that render conditionally (like `<!-- wp:post-featured-image -->`) use `s-directive` elements. See the MCP tool documentation for the sibling pattern — create an opening directive, content elements, then a closing directive as siblings.
213
-
214
- Common WordPress conditionals to convert (use `$item` inside loops):
215
- - `<!-- wp:post-featured-image -->` → `@if($item->featured_image)` ... `@endif`
216
- - `<!-- wp:post-excerpt -->` → `@if($item->post_excerpt)` ... `@endif`
217
- - `<!-- wp:post-comments -->` → `@if($item->comments->count() > 0)` ... `@endif`
218
- - `<!-- wp:query-no-results -->` → `@if($posts->isEmpty())` ... `@endif` (outside loop)
219
-
220
- **Iteration (The Loop):**
278
+ ```php
279
+ // Custom post type archives and singles
280
+ Route::get('/projects', [ProjectController::class, 'index'])->name('projects.index');
281
+ Route::get('/projects/{project}', [ProjectController::class, 'show'])->name('projects.show');
221
282
 
222
- WordPress's "The Loop" (`have_posts() / the_post()`) maps to `@foreach` directives. Use `s-directive` elements for the opening `@foreach` and closing `@endforeach`.
283
+ // Custom taxonomy archives
284
+ Route::get('/project-type/{projectType}', [ProjectTypeController::class, 'show'])->name('project-types.show');
285
+ ```
223
286
 
224
- **IMPORTANT - Loop Variable:** The default loop variable is `$item`. When creating elements inside a loop:
225
- 1. Do NOT pass raw Blade syntax to `html_to_elements` — it will be stored literally
226
- 2. Create clean HTML first, then use `update_element` to add dynamic attributes:
227
- - `textField: "title"` → outputs `{{ $item->title }}`
228
- - `hrefField: "slug"` → outputs `href="{{ $item->slug }}"`
229
- - `srcField: "featured_image"` → outputs `src="{{ $item->featured_image }}"`
230
- 3. For complex expressions (route helpers, method calls), use:
231
- - `hrefExpression: "{{ route('posts.show', $item->slug) }}"`
232
- - `srcExpression: "{{ $item->featured_image }}"`
233
- 4. For text with Blade code, create a statement with `create_statement_with_code`, then add its UUID to the element's `statements` array via `update_element`
287
+ ## Step 4 Document Manual Tasks
234
288
 
235
- Example loop structure using `s-directive` siblings:
236
- ```
237
- 1. s-directive with statement: "@foreach($posts as $item)"
238
- 2. article element (content to repeat)
239
- 3. s-directive with statement: "@endforeach"
240
- ```
289
+ Create a summary of items requiring manual attention:
241
290
 
242
- ### 5f. Create Partials & Components
243
- Convert template-parts/ files into Blade partials using `@include`. Static partials receive data via the second argument: `@include('partials.post-card', ['post' => $post])`. If a template part relies on JavaScript for interactivity (e.g. a slider, a filterable gallery, a live search form), create a Vue component instead and ensure it is registered and mounted in `app.js`.
291
+ ### Forms
292
+ List each form found with fields and purpose. The user will need to recreate these using Laravel form handling or a package like Laravel Livewire.
244
293
 
245
- ### 5g. Style with Tailwind
246
- Do not try to port WordPress CSS. Read the visual intent from the theme's CSS/theme.json and apply Tailwind utility classes directly in the Blade templates. For example:
247
- - WordPress container `<div class="max-w-4xl mx-auto px-4">`
248
- - WordPress navigation `<nav class="flex items-center gap-6">`
249
- - WordPress post grid → `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">`
294
+ ### Shortcodes in Content
295
+ List shortcodes found and their apparent purpose. These will need to be:
296
+ 1. Processed during content migration (find/replace with HTML)
297
+ 2. Or converted to Blade components if they need to remain dynamic
250
298
 
251
- ## Step 6 — Review (Optional)
299
+ ### Plugin Functionality
300
+ For significant plugins (WooCommerce, membership plugins, booking systems), note that this functionality needs separate planning and is outside the scope of this import.
252
301
 
253
- If requested, summarize what was created and note any WordPress features that couldn't be mapped.
302
+ ### Content Migration
303
+ Note that content migration is a separate step. The user will need to:
304
+ 1. Export content from WordPress (WP-CLI, plugin, or direct SQL)
305
+ 2. Transform data to match new schema
306
+ 3. Import into Laravel database
307
+ 4. Process/clean embedded shortcodes
308
+ 5. Migrate media files and update URLs
254
309
 
255
310
  ## Important Rules
256
311
 
257
- - **Blade for SSR, Vue for interactivity.** If the WordPress source is server-rendered PHP (posts, pages, archives, menus, layouts), create Blade templates using `@extends`, `@section`, `@include`, `@foreach`, `{{ }}` and `{!! !!}`. If the WordPress source uses JavaScript for interactivity (AJAX, dynamic filtering, sliders, modals, live search, infinite scroll), create a Vue component. When creating Vue components, ensure they are registered and mounted in `app.js` via `createApp` — do not just import them.
258
- - **Do not ask questions** except the two permitted in Step 1 (which theme, and which database mode). Make reasonable decisions and document them.
259
- - **Work file by file** — read a WordPress file, create the Stellify equivalent, move to the next.
260
- - **Show progress** — print what you're reading and what you're creating as you go.
261
- - **Handle block themes** — if theme.json exists and templates are in HTML with block markup (`<!-- wp:xxx -->`), parse the block structure rather than traditional PHP templates. The output is still Blade (or Vue where the block is interactive).
262
- - **Style with Tailwind** — do not port WordPress CSS. Interpret the visual intent and use Tailwind utilities.
263
- - **Be pragmatic** — focus on the core templates that define the site's main pages. Skip hyper-specific template variations unless they're clearly important.
264
- - **Content handling depends on database mode** — In Mode A (existing DB), the content is already there via the WordPress tables. In Mode B (fresh DB), content is separate and can be migrated later.
312
+ - **Analysis first** Always complete the full analysis before generating any code
313
+ - **Only generate custom elements** Standard WordPress models come from the scaffold
314
+ - **Fresh database only** — This skill assumes a clean Laravel database, not connecting to WordPress tables
315
+ - **No template conversion** — Visual design/styling is handled by a separate skill
316
+ - **Document unknowns** — Flag anything that can't be automatically converted
317
+ - **Be pragmatic** — Focus on post types and taxonomies actually in use (have content), not just registered