@stellisoft/stellify-mcp 0.1.35 → 0.1.36
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 +81 -7
- package/dist/index.js +31 -11
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/wordpress-import.md +57 -111
package/README.md
CHANGED
|
@@ -374,12 +374,80 @@ Create a new UI element. Provide either `page` (route UUID) for root elements, o
|
|
|
374
374
|
**Parameters:**
|
|
375
375
|
- `type` (required): Element type - one of:
|
|
376
376
|
- HTML5: `s-wrapper`, `s-input`, `s-form`, `s-svg`, `s-shape`, `s-media`, `s-iframe`
|
|
377
|
-
- Components: `s-
|
|
377
|
+
- Components: `s-transition`, `s-freestyle`, `s-motion`
|
|
378
378
|
- Blade: `s-directive`
|
|
379
379
|
- Shadcn/ui: `s-chart`, `s-table`, `s-combobox`, `s-accordion`, `s-calendar`, `s-contiguous`
|
|
380
380
|
- `page` (optional): UUID of the page/route (for root elements)
|
|
381
381
|
- `parent` (optional): UUID of the parent element (for child elements)
|
|
382
382
|
|
|
383
|
+
**Using `s-directive` for Blade Conditionals:**
|
|
384
|
+
|
|
385
|
+
`s-directive` elements output Blade directives (like `@if`, `@foreach`, `@endif`). They are **sibling elements** — they don't wrap children. To conditionally render content:
|
|
386
|
+
|
|
387
|
+
1. Create an `s-directive` element with a statement for the opening directive (e.g., `@if(...)`)
|
|
388
|
+
2. Create the content element(s) as the **next sibling(s)**
|
|
389
|
+
3. Create another `s-directive` element with a statement for the closing directive (e.g., `@endif`)
|
|
390
|
+
|
|
391
|
+
Example — conditionally showing an image:
|
|
392
|
+
```
|
|
393
|
+
// 1. Create statement for @if
|
|
394
|
+
create_statement_with_code({
|
|
395
|
+
file: "<file-uuid>",
|
|
396
|
+
code: "@if($item->featured_image)"
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
// 2. Create opening directive element and set its statement
|
|
400
|
+
create_element({ type: "s-directive", page: "<route-uuid>" })
|
|
401
|
+
update_element({ uuid: "<if-directive-uuid>", data: { "statement": "<if-statement-uuid>" } })
|
|
402
|
+
|
|
403
|
+
// 3. Create the image as the next sibling
|
|
404
|
+
html_to_elements({ page: "<route-uuid>", elements: "<img class=\"w-full\" />" })
|
|
405
|
+
// Then update with dynamic src:
|
|
406
|
+
update_element({ uuid: "<img-uuid>", data: { "srcField": "featured_image" } })
|
|
407
|
+
|
|
408
|
+
// 4. Create statement for @endif
|
|
409
|
+
create_statement_with_code({ file: "<file-uuid>", code: "@endif" })
|
|
410
|
+
|
|
411
|
+
// 5. Create closing directive element
|
|
412
|
+
create_element({ type: "s-directive", page: "<route-uuid>" })
|
|
413
|
+
update_element({ uuid: "<endif-directive-uuid>", data: { "statement": "<endif-statement-uuid>" } })
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The three elements render in order as siblings:
|
|
417
|
+
```blade
|
|
418
|
+
@if($item->featured_image)
|
|
419
|
+
<img class="w-full" src="{{ $item->featured_image }}" />
|
|
420
|
+
@endif
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Using `s-directive` for Loops:**
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
// 1. Create @foreach directive
|
|
427
|
+
create_statement_with_code({ file: "<file-uuid>", code: "@foreach($posts as $item)" })
|
|
428
|
+
create_element({ type: "s-directive", page: "<route-uuid>" })
|
|
429
|
+
update_element({ uuid: "<foreach-uuid>", data: { "statement": "<foreach-statement-uuid>" } })
|
|
430
|
+
|
|
431
|
+
// 2. Create loop content (article with dynamic fields)
|
|
432
|
+
html_to_elements({ page: "<route-uuid>", elements: "<article><h2></h2><p></p></article>" })
|
|
433
|
+
// Update elements to use loop item fields:
|
|
434
|
+
update_element({ uuid: "<h2-uuid>", data: { "textField": "title" } }) // → {{ $item->title }}
|
|
435
|
+
update_element({ uuid: "<p-uuid>", data: { "textField": "excerpt" } }) // → {{ $item->excerpt }}
|
|
436
|
+
|
|
437
|
+
// 3. Create @endforeach directive
|
|
438
|
+
create_statement_with_code({ file: "<file-uuid>", code: "@endforeach" })
|
|
439
|
+
create_element({ type: "s-directive", page: "<route-uuid>" })
|
|
440
|
+
update_element({ uuid: "<endforeach-uuid>", data: { "statement": "<endforeach-statement-uuid>" } })
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Loop Item Attributes:**
|
|
444
|
+
Inside `@foreach` loops, use these attributes on elements to reference `$item`:
|
|
445
|
+
- `textField: "fieldName"` → outputs `{{ $item->fieldName }}`
|
|
446
|
+
- `hrefField: "fieldName"` → outputs `href="{{ $item->fieldName }}"`
|
|
447
|
+
- `srcField: "fieldName"` → outputs `src="{{ $item->fieldName }}"`
|
|
448
|
+
- `hrefExpression: "{{ route('posts.show', $item->slug) }}"` → for complex expressions
|
|
449
|
+
- `srcExpression`, `altExpression` → same pattern for other attributes
|
|
450
|
+
|
|
383
451
|
---
|
|
384
452
|
|
|
385
453
|
#### `update_element`
|
|
@@ -397,7 +465,18 @@ Update an existing UI element.
|
|
|
397
465
|
- `locked`: Prevent editing (boolean)
|
|
398
466
|
- `tag`: HTML tag (div, input, button, etc.)
|
|
399
467
|
- `classes`: CSS classes array `["class1", "class2"]`
|
|
400
|
-
- `text`:
|
|
468
|
+
- `text`: Static text content
|
|
469
|
+
- `statements`: Array of statement UUIDs for dynamic Blade content
|
|
470
|
+
|
|
471
|
+
**Loop item fields** (for elements inside `@foreach` loops, references `$item`):
|
|
472
|
+
- `textField`: Field name → outputs `{{ $item->fieldName }}`
|
|
473
|
+
- `hrefField`: Field name → outputs `href="{{ $item->fieldName }}"`
|
|
474
|
+
- `srcField`: Field name → outputs `src="{{ $item->fieldName }}"`
|
|
475
|
+
|
|
476
|
+
**Expression attributes** (for complex Blade expressions):
|
|
477
|
+
- `hrefExpression`: Full Blade expression for href (e.g., `"{{ route('posts.show', $item->slug) }}"`)
|
|
478
|
+
- `srcExpression`: Full Blade expression for src
|
|
479
|
+
- `altExpression`: Full Blade expression for alt
|
|
401
480
|
|
|
402
481
|
**Event handlers** (set value to method UUID):
|
|
403
482
|
- `click`: @click
|
|
@@ -480,11 +559,6 @@ html_to_elements(page: routeUUID, elements: "<main>...</main>")
|
|
|
480
559
|
html_to_elements(page: routeUUID, elements: "<footer>...</footer>")
|
|
481
560
|
```
|
|
482
561
|
|
|
483
|
-
**Alternative approach (wrap in a single container):**
|
|
484
|
-
```
|
|
485
|
-
html_to_elements(page: routeUUID, elements: "<div class='min-h-screen flex flex-col'><header>...</header><main>...</main><footer>...</footer></div>")
|
|
486
|
-
```
|
|
487
|
-
|
|
488
562
|
**Features:**
|
|
489
563
|
- Parses HTML structure
|
|
490
564
|
- Creates all elements with proper nesting
|
package/dist/index.js
CHANGED
|
@@ -569,16 +569,15 @@ Use the returned UUID with html_to_elements (page parameter) or get_route for fu
|
|
|
569
569
|
},
|
|
570
570
|
{
|
|
571
571
|
name: 'create_element',
|
|
572
|
-
description: `Create a UI element. Provide page (route UUID) for root elements, or parent (element UUID) for children
|
|
572
|
+
description: `Create a UI element. Provide page (route UUID) for root elements, or parent (element UUID) for children.`,
|
|
573
573
|
inputSchema: {
|
|
574
574
|
type: 'object',
|
|
575
575
|
properties: {
|
|
576
576
|
type: {
|
|
577
577
|
type: 'string',
|
|
578
578
|
enum: [
|
|
579
|
-
's-wrapper', 's-input', 's-form', 's-svg', 's-shape', 's-media',
|
|
580
|
-
's-
|
|
581
|
-
's-directive'
|
|
579
|
+
's-wrapper', 's-input', 's-form', 's-svg', 's-shape', 's-media',
|
|
580
|
+
's-freestyle', 's-directive'
|
|
582
581
|
],
|
|
583
582
|
description: 'Element type - must be one of the valid Stellify element types',
|
|
584
583
|
},
|
|
@@ -596,7 +595,24 @@ Use the returned UUID with html_to_elements (page parameter) or get_route for fu
|
|
|
596
595
|
},
|
|
597
596
|
{
|
|
598
597
|
name: 'update_element',
|
|
599
|
-
description: `Update a UI element. Data object: tag, classes, text, event handlers (method UUIDs), classBindings. Set 'name' on root elements to create Blade views (e.g., name="notes.index" for view('notes.index'))
|
|
598
|
+
description: `Update a UI element. Data object: tag, classes, text, event handlers (method UUIDs), classBindings. Set 'name' on root elements to create Blade views (e.g., name="notes.index" for view('notes.index')).
|
|
599
|
+
|
|
600
|
+
**For elements inside @foreach loops (SSR/Blade):**
|
|
601
|
+
Use these attributes to reference the loop variable (defaults to \`$item\`):
|
|
602
|
+
- \`textField\`: Field name for text content → outputs \`{{ $item->fieldName }}\`
|
|
603
|
+
- \`hrefField\`: Field name for href → outputs \`href="{{ $item->fieldName }}"\`
|
|
604
|
+
- \`srcField\`: Field name for src → outputs \`src="{{ $item->fieldName }}"\`
|
|
605
|
+
|
|
606
|
+
**For complex Blade expressions in attributes:**
|
|
607
|
+
Use expression attributes when you need more than simple field access (e.g., route helpers, method calls):
|
|
608
|
+
- \`hrefExpression\`: Blade expression for href → outputs \`href="..."\` with the expression
|
|
609
|
+
- \`srcExpression\`: Blade expression for src → outputs \`src="..."\` with the expression
|
|
610
|
+
- \`altExpression\`: Blade expression for alt → outputs \`alt="..."\` with the expression
|
|
611
|
+
|
|
612
|
+
Example: \`hrefExpression: "{{ route('posts.show', $item->slug) }}"\`
|
|
613
|
+
|
|
614
|
+
**For Blade text content:**
|
|
615
|
+
Use the \`statements\` array with statement UUIDs containing Blade code. The statement's \`code\` property will be output directly for Blade to evaluate.`,
|
|
600
616
|
inputSchema: {
|
|
601
617
|
type: 'object',
|
|
602
618
|
properties: {
|
|
@@ -718,12 +734,16 @@ When HTML contains multiple root-level elements (e.g., <header>, <main>, <footer
|
|
|
718
734
|
**@click auto-wiring:** Pass 'file' UUID to auto-resolve @click="methodName" handlers. Methods must exist in the file first.
|
|
719
735
|
|
|
720
736
|
**Blade Syntax Handling:**
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
737
|
+
For SSR/Blade pages, do NOT pass raw Blade expressions in text or attributes. The HTML parser stores them literally which causes rendering issues. Instead:
|
|
738
|
+
|
|
739
|
+
1. **For static HTML:** Pass clean HTML without Blade syntax, then use \`update_element\` to add dynamic behavior
|
|
740
|
+
2. **For loop content:** After creating elements, use \`update_element\` with:
|
|
741
|
+
- \`textField\`, \`hrefField\`, \`srcField\` for simple field access (outputs \`{{ $item->field }}\`)
|
|
742
|
+
- \`hrefExpression\`, \`srcExpression\`, \`altExpression\` for complex expressions
|
|
743
|
+
- \`statements\` array with statement UUIDs for text content with Blade code
|
|
744
|
+
3. **For conditionals:** Use \`s-directive\` elements as siblings (see update_element docs)
|
|
725
745
|
|
|
726
|
-
|
|
746
|
+
**Loop variable:** Inside \`@foreach\` loops created with \`s-directive\`, the default loop variable is \`$item\`. Use \`textField: "title"\` to output \`{{ $item->title }}\`.
|
|
727
747
|
|
|
728
748
|
Prefer SVG icons over emoji (encoding issues).`,
|
|
729
749
|
inputSchema: {
|
|
@@ -1477,7 +1497,7 @@ const SERVER_INSTRUCTIONS = `Stellify is a coding platform where code is stored
|
|
|
1477
1497
|
// Create MCP server
|
|
1478
1498
|
const server = new Server({
|
|
1479
1499
|
name: 'stellify-mcp',
|
|
1480
|
-
version: '0.1.
|
|
1500
|
+
version: '0.1.36',
|
|
1481
1501
|
}, {
|
|
1482
1502
|
capabilities: {
|
|
1483
1503
|
tools: {},
|
package/package.json
CHANGED
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.
|
|
9
|
+
"version": "0.1.36",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@stellisoft/stellify-mcp",
|
|
14
|
-
"version": "0.1.
|
|
14
|
+
"version": "0.1.36",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
|
@@ -12,10 +12,6 @@ You are importing a WordPress site into Stellify by reading its PHP theme files
|
|
|
12
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
14
|
|
|
15
|
-
## Step 0 — Discover Tools
|
|
16
|
-
|
|
17
|
-
List all available Stellify MCP tools. Understand what each tool does, what parameters it requires, and any dependencies between them (e.g. you need a file before you can add methods to it, you need a method before you can add statements). Print a summary of the tools and their creation order.
|
|
18
|
-
|
|
19
15
|
## Step 1 — Identify the Active Theme
|
|
20
16
|
|
|
21
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.
|
|
@@ -60,60 +56,13 @@ Read functions.php thoroughly. Extract:
|
|
|
60
56
|
|
|
61
57
|
## Step 4 — Plan the Laravel Structure
|
|
62
58
|
|
|
63
|
-
Before calling any Stellify tools,
|
|
64
|
-
|
|
65
|
-
### Models
|
|
66
|
-
- Post (always — WordPress core)
|
|
67
|
-
- Page (always — WordPress core)
|
|
68
|
-
- Category, Tag (if used)
|
|
69
|
-
- Any custom post types found in Step 3
|
|
70
|
-
- User (if the theme has author pages)
|
|
71
|
-
|
|
72
|
-
### Controllers
|
|
73
|
-
- PostController (index, show) — handles blog listing and single posts
|
|
74
|
-
- PageController (show) — handles static pages
|
|
75
|
-
- One controller per custom post type
|
|
76
|
-
- HomeController — if front-page.php or a static homepage exists
|
|
77
|
-
- SearchController — if search.php exists
|
|
78
|
-
|
|
79
|
-
### Routes (web.php)
|
|
80
|
-
Map the WordPress URL structure:
|
|
81
|
-
- `/` → HomeController or PostController@index
|
|
82
|
-
- `/blog` or `/posts` → PostController@index (if static homepage)
|
|
83
|
-
- `/{post-slug}` → PostController@show
|
|
84
|
-
- `/{page-slug}` → PageController@show
|
|
85
|
-
- `/category/{slug}` → PostController@index (filtered)
|
|
86
|
-
- `/tag/{slug}` → PostController@index (filtered)
|
|
87
|
-
- `/search` → SearchController@index
|
|
88
|
-
- Custom post type archives and singles
|
|
89
|
-
|
|
90
|
-
### Blade Views
|
|
91
|
-
Everything is Blade. The directory structure should be:
|
|
92
|
-
```
|
|
93
|
-
layouts/
|
|
94
|
-
app.blade.php ← from header.php + footer.php
|
|
95
|
-
posts/
|
|
96
|
-
index.blade.php ← from archive.php or index.php
|
|
97
|
-
show.blade.php ← from single.php
|
|
98
|
-
pages/
|
|
99
|
-
show.blade.php ← from page.php
|
|
100
|
-
partials/
|
|
101
|
-
nav.blade.php ← from wp_nav_menu output
|
|
102
|
-
sidebar.blade.php ← from sidebar.php
|
|
103
|
-
post-card.blade.php ← from template-parts/content.php
|
|
104
|
-
comments.blade.php ← from comments.php
|
|
105
|
-
search-form.blade.php ← from searchform.php
|
|
106
|
-
errors/
|
|
107
|
-
404.blade.php ← from 404.php
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Migrations (Mode B only)
|
|
111
|
-
If the user chose Mode B (fresh database), plan one migration per model with fields derived from:
|
|
112
|
-
- WordPress core fields: title, slug, content, excerpt, featured_image, status, published_at
|
|
113
|
-
- Custom fields from `get_post_meta()` calls found in templates
|
|
114
|
-
- Any ACF or custom meta boxes registered in functions.php
|
|
59
|
+
Before calling any Stellify tools, plan:
|
|
115
60
|
|
|
116
|
-
|
|
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
|
|
117
66
|
|
|
118
67
|
## Step 5 — Build in Stellify (Order of Operations)
|
|
119
68
|
|
|
@@ -211,52 +160,58 @@ Translate WordPress functions to Blade:
|
|
|
211
160
|
- `language_attributes()` → `lang="{{ str_replace('_', '-', app()->getLocale()) }}"`
|
|
212
161
|
|
|
213
162
|
### 5e. Create Blade Views
|
|
214
|
-
For each WordPress template file, read the PHP and create the equivalent Blade view
|
|
163
|
+
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')`.**
|
|
164
|
+
|
|
165
|
+
**⚠️ 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.
|
|
215
166
|
|
|
216
167
|
**WordPress → Blade translation guide:**
|
|
217
168
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|-----------|------------------------------|---------------------------|
|
|
222
|
-
| `the_title()` | `{{ $post->post_title }}` | `{{ $post->title }}` |
|
|
223
|
-
| `the_content()` | `{!! $post->post_content !!}` | `{!! $post->content !!}` |
|
|
224
|
-
| `the_excerpt()` | `{{ $post->post_excerpt }}` | `{{ $post->excerpt }}` |
|
|
225
|
-
| `the_permalink()` | `{{ route('posts.show', $post->post_name) }}` | `{{ route('posts.show', $post->slug) }}` |
|
|
226
|
-
| `the_post_thumbnail()` | via `wp_postmeta` lookup | `<img src="{{ asset('storage/' . $post->featured_image) }}" />` |
|
|
227
|
-
| `the_date()` / `the_time()` | `{{ \Carbon\Carbon::parse($post->post_date)->format('d M Y') }}` | `{{ $post->published_at->format('d M Y') }}` |
|
|
228
|
-
| `the_author()` | `{{ $post->author->display_name }}` | `{{ $post->author->name }}` |
|
|
229
|
-
| `comments_template()` | `@include('partials.comments', ['post' => $post])` | same |
|
|
230
|
-
| `get_template_part('content')` | `@include('partials.post-card', ['post' => $post])` | same |
|
|
231
|
-
| `have_posts() / the_post()` | Use an `s-loop` element (see below) | same |
|
|
232
|
-
| `wp_link_pages()` | `{{ $posts->links() }}` | same |
|
|
233
|
-
| `get_search_form()` | `@include('partials.search-form')` | same |
|
|
234
|
-
| `wp_nav_menu()` | `@include('partials.nav')` | same |
|
|
235
|
-
| `get_header()` / `get_footer()` | handled by `@extends('layouts.app')` | same |
|
|
236
|
-
| `esc_html()` / `esc_attr()` | `{{ }}` (Blade auto-escapes) | same |
|
|
237
|
-
| `wp_kses_post()` | `{!! !!}` (for trusted HTML content) | same |
|
|
238
|
-
|
|
239
|
-
**Stellify `s-loop` elements for iteration:**
|
|
240
|
-
|
|
241
|
-
WordPress's "The Loop" (`have_posts() / the_post()`) requires two things in Stellify:
|
|
242
|
-
|
|
243
|
-
1. **Set the element type to `s-loop`** using `update_element` with `type: "s-loop"` and `variable` set to the collection name from the controller's return array. This tells Stellify to iterate over that variable and pass each item as `$item` to child elements.
|
|
244
|
-
|
|
245
|
-
2. **Write the `@foreach` in the Blade template as well.** The Blade content inside the element still needs the `@foreach` loop.
|
|
246
|
-
|
|
247
|
-
Example: If the controller returns `['posts' => Post::paginate(10)]`, the element that lists posts should be updated to:
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"uuid": "<element-uuid>",
|
|
251
|
-
"data": {
|
|
252
|
-
"type": "s-loop",
|
|
253
|
-
"variable": "posts"
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
And the Blade content inside uses `@foreach($posts as $post)` ... `@endforeach` as normal.
|
|
169
|
+
Mode A uses WordPress column names; Mode B uses clean Laravel names.
|
|
170
|
+
|
|
171
|
+
**IMPORTANT:** Inside `@foreach` loops, use `$item` as the loop variable. This matches the Stellify assembler's expectations for `textField`, `hrefField`, `srcField` attributes.
|
|
258
172
|
|
|
259
|
-
|
|
173
|
+
| WordPress | Blade (Mode A) | Blade (Mode B) | Stellify Attribute |
|
|
174
|
+
|-----------|----------------|----------------|-------------------|
|
|
175
|
+
| `the_title()` | `{{ $item->post_title }}` | `{{ $item->title }}` | `textField: "title"` |
|
|
176
|
+
| `the_content()` | `{!! $item->post_content !!}` | `{!! $item->content !!}` | statement with code |
|
|
177
|
+
| `the_excerpt()` | `{{ $item->post_excerpt }}` | `{{ $item->excerpt }}` | `textField: "excerpt"` |
|
|
178
|
+
| `the_permalink()` | `{{ route('posts.show', $item->post_name) }}` | `{{ route('posts.show', $item->slug) }}` | `hrefExpression: "..."` |
|
|
179
|
+
| `the_date()` | `{{ $item->post_date->format('d M Y') }}` | `{{ $item->published_at->format('d M Y') }}` | statement with code |
|
|
180
|
+
| `the_author()` | `{{ $item->author->display_name }}` | `{{ $item->author->name }}` | statement with code |
|
|
181
|
+
| `get_template_part()` | `@include('partials.post-card', ['post' => $item])` | same | s-directive |
|
|
182
|
+
| `have_posts()` | `@foreach($posts as $item)` | same | s-directive pair |
|
|
183
|
+
|
|
184
|
+
**Conditional Rendering with `s-directive`:**
|
|
185
|
+
|
|
186
|
+
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.
|
|
187
|
+
|
|
188
|
+
Common WordPress conditionals to convert (use `$item` inside loops):
|
|
189
|
+
- `<!-- wp:post-featured-image -->` → `@if($item->featured_image)` ... `@endif`
|
|
190
|
+
- `<!-- wp:post-excerpt -->` → `@if($item->post_excerpt)` ... `@endif`
|
|
191
|
+
- `<!-- wp:post-comments -->` → `@if($item->comments->count() > 0)` ... `@endif`
|
|
192
|
+
- `<!-- wp:query-no-results -->` → `@if($posts->isEmpty())` ... `@endif` (outside loop)
|
|
193
|
+
|
|
194
|
+
**Iteration (The Loop):**
|
|
195
|
+
|
|
196
|
+
WordPress's "The Loop" (`have_posts() / the_post()`) maps to `@foreach` directives. Use `s-directive` elements for the opening `@foreach` and closing `@endforeach`.
|
|
197
|
+
|
|
198
|
+
**IMPORTANT - Loop Variable:** The default loop variable is `$item`. When creating elements inside a loop:
|
|
199
|
+
1. Do NOT pass raw Blade syntax to `html_to_elements` — it will be stored literally
|
|
200
|
+
2. Create clean HTML first, then use `update_element` to add dynamic attributes:
|
|
201
|
+
- `textField: "title"` → outputs `{{ $item->title }}`
|
|
202
|
+
- `hrefField: "slug"` → outputs `href="{{ $item->slug }}"`
|
|
203
|
+
- `srcField: "featured_image"` → outputs `src="{{ $item->featured_image }}"`
|
|
204
|
+
3. For complex expressions (route helpers, method calls), use:
|
|
205
|
+
- `hrefExpression: "{{ route('posts.show', $item->slug) }}"`
|
|
206
|
+
- `srcExpression: "{{ $item->featured_image }}"`
|
|
207
|
+
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`
|
|
208
|
+
|
|
209
|
+
Example loop structure using `s-directive` siblings:
|
|
210
|
+
```
|
|
211
|
+
1. s-directive with statement: "@foreach($posts as $item)"
|
|
212
|
+
2. article element (content to repeat)
|
|
213
|
+
3. s-directive with statement: "@endforeach"
|
|
214
|
+
```
|
|
260
215
|
|
|
261
216
|
### 5f. Create Partials & Components
|
|
262
217
|
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`.
|
|
@@ -267,18 +222,9 @@ Do not try to port WordPress CSS. Read the visual intent from the theme's CSS/th
|
|
|
267
222
|
- WordPress navigation → `<nav class="flex items-center gap-6">`
|
|
268
223
|
- WordPress post grid → `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">`
|
|
269
224
|
|
|
270
|
-
## Step 6 — Review
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
- Database mode chosen (A or B)
|
|
274
|
-
- Total models created (and which WordPress tables they map to, if Mode A)
|
|
275
|
-
- Total controllers and methods
|
|
276
|
-
- Total routes
|
|
277
|
-
- Total Blade views and partials
|
|
278
|
-
- Total Vue components (if any) and why each was needed
|
|
279
|
-
- Any WordPress features that could NOT be mapped (e.g. specific plugins, shortcodes with no equivalent)
|
|
280
|
-
- If Mode B: provide a SQL migration query or artisan command to copy content from the WordPress database to the new schema
|
|
281
|
-
- Suggestions for manual follow-up
|
|
225
|
+
## Step 6 — Review (Optional)
|
|
226
|
+
|
|
227
|
+
If requested, summarize what was created and note any WordPress features that couldn't be mapped.
|
|
282
228
|
|
|
283
229
|
## Important Rules
|
|
284
230
|
|