1. There is currently a PHP Blade code block stored in MySQL, with its code kept in the schema field, as shown in Figure 1.

2. Some variables have already been declared in the PHP script. The code block is shown below.
{
"sections": {
@foreach ($homepage as $id => $section)
{{-- 轮播图 --}}
@if($section['type'] === 'carousel')
"{{ $id }}": {
"type": "carousel",
"settings": {
"loop": true,
"autoplay": true,
"height": "{{ isset($section['slide_height']) && $section['slide_height'] === 'full' ? 'full' : 'auto' }}",
"interval": {{ $section['interval'] }}
},
"blocks": {
@if (isset($section['items']))
@foreach ($section['items'] as $key => $item)
"slide-{{ $key }}": {
"type": "slide",
"settings": {
"image": "{{ @$item['image']['url'] ?: '' }}",
"url": "{{ $item['button']['url'] }}",
"align": "{{ $item['align'] }}",
"title": {-- $item['title'] --},
"description": {-- $item['description'] --},
"button": {-- $item['button']['text'] --},
"opacity": {{ $item['show_overlay'] ? (100 - $item['opacity']) : 100 }},
"button_background_color": "{{ $item['button_background_color'] }}",
"button_color": "{{ $item['button_text_color']}}",
"color": "{{ $item['text_color'] }}"
}
}@if (!$loop->last),@endif
@endforeach
@endif
}
},
@endif
{{-- 商品分类 --}}
@if($section['type'] === 'collection')
"{{ $id }}": {
"type": "main-collections",
"settings": {
"heading": {-- $section['title'] --}
},
"blocks": {
@foreach ($section['ids'] as $key => $item)
"collection-{{ $key }}": {
"type": "collection",
"settings": {
"id": {{ $item }}
}
}@if (!$loop->last),@endif
@endforeach
}
},
@endif
{{-- 精选商品 --}}
@if($section['type'] === 'product')
"{{ $id }}": {
"type": "main-products",
"settings": {
"show_product_palette": {{ @Module::find('ProductPalette')->isEnabled() && @config('product-palette.show_position') === 'all' ? 'true' : 'false' }},
"heading": {-- $section['title'] --},
"layout": "{{ $section['layout'] }}",
"page_size": {{ $section['amount'] }}
},
"blocks": {
@foreach ($section['category'] as $key => $item)
"collection-{{ $key }}": {
"type": "collection",
"settings": {
"id": {{ $item }}
}
}@if (!$loop->last),@endif
@endforeach
}
},
@endif
{{-- 邮件订阅 --}}
@if($section['type'] === 'subscribe')
"{{ $id }}": {
"type": "apps",
"blocks": {
"newsletter": {
"type": "object/Newsletter/blocks/newsletter",
"settings": {
"heading": {-- $section['title'] --},
"description": {-- $section['description'] --}
}
}
}
},
@endif
{{-- 图片 --}}
@if($section['type'] === 'image')
"{{ $id }}": {
"type": "image",
"settings": {
"heading": {-- $section['title'] --},
"heading_align": "{{ $section['align'] }}"
},
"blocks": {
@if (isset($section['items']))
@foreach ($section['items'] as $key => $item)
"column-{{ $key }}": {
"type": "column",
"settings": {
"image": "{{ @$item['image']['url'] ?: '' }}",
"mobile_image": "{{ @$item['mb_image']['url'] ?: '' }}",
"url": "{{ $item['url'] }}",
"title": "{{ @$item['url_object']['title'] ?: '' }}"
}
}@if (!$loop->last),@endif
@endforeach
@endif
}
},
@endif
{{-- 图文 --}}
@if($section['type'] === 'imagetext')
{{-- 网格 --}}
@if($section['layout_type'] === 'grid')
"{{ $id }}": {
"type": "multi-column",
"settings": {
"heading": {-- $section['title_text'] ?: '' --},
"heading_align": "{{ $section['title_aligns'] }}",
"text_color": "{{ $section['text_color_v2'] }}",
"image_size": "{{ $section['image_style'] === 'auto' ? 'auto' : 'fixed' }}",
"mask_opacity": {{ $section['opacity'] }},
"button_text_color": "{{ $section['button_text_color_v2'] }}",
"button_background_color": "{{ @$section['button_bg_color_v2'] ?: '' }}",
"text_align": "{{ $section['align'] }}"
},
"blocks": {
@if (isset($section['items']))
@foreach ($section['items'] as $key => $item)
"column-{{ $key }}": {
"type": "column",
"settings": {
"heading": {-- $item['title'] ?: '' --},
"text": {-- @$item['description'] ?:'' --},
"image": "{{ @$item['image']['url'] ?: '' }}",
"mobile_image": "{{ @$item['mobile_image']['url'] ?: '' }}",
"url": "{{ @$item['button']['url_object']['url'] }}",
"label": {-- $item['button']['text'] --}
}
}@if (!$loop->last),@endif
@endforeach
@endif
}
},
@else
{{-- 左文右图(left) --}}
{{-- 左图右文(right) --}}
"{{ $id }}": {
"type": "image-text",
"settings": {
"heading": {-- $section['title_text'] --},
"heading_align": "{{ $section['title_aligns'] }}",
"image": "{{ @$section['horizontal']['image']['url'] }}",
"image_placement": "{{ $section['layout_type'] === 'left' ? 'second' : 'first' }}",
"horizontal_align": "{{ $section['horizontal']['level_align'] }}",
"vertical_align": "{{ $section['horizontal']['vertical_align'] === 'flex-start' ? 'top' : ($section['horizontal']['vertical_align'] === 'flex-end' ? 'bottom' : 'middle') }}",
"text_color": "{{ $section['text_color_v2'] }}",
"background_color": "{{ @$section['text_bg_color_v2'] ?: '' }}"
},
"blocks": {
"heading": {
"type": "heading",
"settings": {
"heading": {-- $section['horizontal']['title'] --}
}
},
"text": {
"type": "text",
"settings": {
"text": {-- $section['horizontal']['description'] --}
}
},
"button": {
"type": "button",
"settings": {
"url": "{{ @$section['horizontal']['button']['url_object']['url'] }}",
"label": {-- $section['horizontal']['button']['text'] --},
"text_color": "{{ $section['button_text_color_v2'] }}",
"background_color": "{{ $section['button_bg_color_v2'] }}"
}
}
}
},
@endif
@endif
@endforeach
"0": {
"type": "empty"
}
}
}
3. The compiled template file code is shown below.
{
"sections": {
<?php $__currentLoopData = $homepage; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $id => $section): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if($section['type'] === 'carousel'): ?>
"<?php echo e($id); ?>": {
"type": "carousel",
"settings": {
"loop": true,
"autoplay": true,
"height": "<?php echo e(isset($section['slide_height']) && $section['slide_height'] === 'full' ? 'full' : 'auto'); ?>",
"interval": <?php echo e($section['interval']); ?>
},
"blocks": {
<?php if(isset($section['items'])): ?>
<?php $__currentLoopData = $section['items']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
"slide-<?php echo e($key); ?>": {
"type": "slide",
"settings": {
"image": "<?php echo e(@$item['image']['url'] ?: ''); ?>",
"url": "<?php echo e($item['button']['url']); ?>",
"align": "<?php echo e($item['align']); ?>",
"title": <?php echo json_encode($item['title'], JSON_UNESCAPED_UNICODE); ?>,
"description": <?php echo json_encode($item['description'], JSON_UNESCAPED_UNICODE); ?>,
"button": <?php echo json_encode($item['button']['text'], JSON_UNESCAPED_UNICODE); ?>,
"opacity": <?php echo e($item['show_overlay'] ? (100 - $item['opacity']) : 100); ?>,
"button_background_color": "<?php echo e($item['button_background_color']); ?>",
"button_color": "<?php echo e($item['button_text_color']); ?>",
"color": "<?php echo e($item['text_color']); ?>"
}
}<?php if(!$loop->last): ?>,<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php endif; ?>
}
},
<?php endif; ?>
<?php if($section['type'] === 'collection'): ?>
"<?php echo e($id); ?>": {
"type": "main-collections",
"settings": {
"heading": <?php echo json_encode($section['title'], JSON_UNESCAPED_UNICODE); ?>
},
"blocks": {
<?php $__currentLoopData = $section['ids']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
"collection-<?php echo e($key); ?>": {
"type": "collection",
"settings": {
"id": <?php echo e($item); ?>
}
}<?php if(!$loop->last): ?>,<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
}
},
<?php endif; ?>
<?php if($section['type'] === 'product'): ?>
"<?php echo e($id); ?>": {
"type": "main-products",
"settings": {
"show_product_palette": <?php echo e(@Module::find('ProductPalette')->isEnabled() && @config('product-palette.show_position') === 'all' ? 'true' : 'false'); ?>,
"heading": <?php echo json_encode($section['title'], JSON_UNESCAPED_UNICODE); ?>,
"layout": "<?php echo e($section['layout']); ?>",
"page_size": <?php echo e($section['amount']); ?>
},
"blocks": {
<?php $__currentLoopData = $section['category']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
"collection-<?php echo e($key); ?>": {
"type": "collection",
"settings": {
"id": <?php echo e($item); ?>
}
}<?php if(!$loop->last): ?>,<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
}
},
<?php endif; ?>
<?php if($section['type'] === 'subscribe'): ?>
"<?php echo e($id); ?>": {
"type": "apps",
"blocks": {
"newsletter": {
"type": "object/Newsletter/blocks/newsletter",
"settings": {
"heading": <?php echo json_encode($section['title'], JSON_UNESCAPED_UNICODE); ?>,
"description": <?php echo json_encode($section['description'], JSON_UNESCAPED_UNICODE); ?>
}
}
}
},
<?php endif; ?>
<?php if($section['type'] === 'image'): ?>
"<?php echo e($id); ?>": {
"type": "image",
"settings": {
"heading": <?php echo json_encode($section['title'], JSON_UNESCAPED_UNICODE); ?>,
"heading_align": "<?php echo e($section['align']); ?>"
},
"blocks": {
<?php if(isset($section['items'])): ?>
<?php $__currentLoopData = $section['items']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
"column-<?php echo e($key); ?>": {
"type": "column",
"settings": {
"image": "<?php echo e(@$item['image']['url'] ?: ''); ?>",
"mobile_image": "<?php echo e(@$item['mb_image']['url'] ?: ''); ?>",
"url": "<?php echo e($item['url']); ?>",
"title": "<?php echo e(@$item['url_object']['title'] ?: ''); ?>"
}
}<?php if(!$loop->last): ?>,<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php endif; ?>
}
},
<?php endif; ?>
<?php if($section['type'] === 'imagetext'): ?>
<?php if($section['layout_type'] === 'grid'): ?>
"<?php echo e($id); ?>": {
"type": "multi-column",
"settings": {
"heading": <?php echo json_encode($section['title_text'] ?: '', JSON_UNESCAPED_UNICODE); ?>,
"heading_align": "<?php echo e($section['title_aligns']); ?>",
"text_color": "<?php echo e($section['text_color_v2']); ?>",
"image_size": "<?php echo e($section['image_style'] === 'auto' ? 'auto' : 'fixed'); ?>",
"mask_opacity": <?php echo e($section['opacity']); ?>,
"button_text_color": "<?php echo e($section['button_text_color_v2']); ?>",
"button_background_color": "<?php echo e(@$section['button_bg_color_v2'] ?: ''); ?>",
"text_align": "<?php echo e($section['align']); ?>"
},
"blocks": {
<?php if(isset($section['items'])): ?>
<?php $__currentLoopData = $section['items']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
"column-<?php echo e($key); ?>": {
"type": "column",
"settings": {
"heading": <?php echo json_encode($item['title'] ?: '', JSON_UNESCAPED_UNICODE); ?>,
"text": <?php echo json_encode(@$item['description'] ?:'', JSON_UNESCAPED_UNICODE); ?>,
"image": "<?php echo e(@$item['image']['url'] ?: ''); ?>",
"mobile_image": "<?php echo e(@$item['mobile_image']['url'] ?: ''); ?>",
"url": "<?php echo e(@$item['button']['url_object']['url']); ?>",
"label": <?php echo json_encode($item['button']['text'], JSON_UNESCAPED_UNICODE); ?>
}
}<?php if(!$loop->last): ?>,<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php endif; ?>
}
},
<?php else: ?>
"<?php echo e($id); ?>": {
"type": "image-text",
"settings": {
"heading": <?php echo json_encode($section['title_text'], JSON_UNESCAPED_UNICODE); ?>,
"heading_align": "<?php echo e($section['title_aligns']); ?>",
"image": "<?php echo e(@$section['horizontal']['image']['url']); ?>",
"image_placement": "<?php echo e($section['layout_type'] === 'left' ? 'second' : 'first'); ?>",
"horizontal_align": "<?php echo e($section['horizontal']['level_align']); ?>",
"vertical_align": "<?php echo e($section['horizontal']['vertical_align'] === 'flex-start' ? 'top' : ($section['horizontal']['vertical_align'] === 'flex-end' ? 'bottom' : 'middle')); ?>",
"text_color": "<?php echo e($section['text_color_v2']); ?>",
"background_color": "<?php echo e(@$section['text_bg_color_v2'] ?: ''); ?>"
},
"blocks": {
"heading": {
"type": "heading",
"settings": {
"heading": <?php echo json_encode($section['horizontal']['title'], JSON_UNESCAPED_UNICODE); ?>
}
},
"text": {
"type": "text",
"settings": {
"text": <?php echo json_encode($section['horizontal']['description'], JSON_UNESCAPED_UNICODE); ?>
}
},
"button": {
"type": "button",
"settings": {
"url": "<?php echo e(@$section['horizontal']['button']['url_object']['url']); ?>",
"label": <?php echo json_encode($section['horizontal']['button']['text'], JSON_UNESCAPED_UNICODE); ?>,
"text_color": "<?php echo e($section['button_text_color_v2']); ?>",
"background_color": "<?php echo e($section['button_bg_color_v2']); ?>"
}
}
}
},
<?php endif; ?>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
"0": {
"type": "empty"
}
}
}
4. I decided to skip the step of compiling the PHP Blade file into a PHP template file, and instead manually adjust it to the compiled format and then remove the Blade syntax. Below is an example of a compiled Blade format. As shown in Figure 2.

5. Below is an example after removing the Blade syntax. Variables like $__env have all been deleted. As shown in Figure 3.

6. I decided to first try writing a simple code block to verify the feasibility of the technical approach. If it works, I will then try to execute the code block generated in step 5.
{
<?php $items = [1, 2, 3]; ?>
<?php if(isset($items)): ?>
<?php $count = count($items); foreach($items as $key => $item): $count--; ?>
"slide-<?php echo $key; ?>": {
"type": "slide",
"settings": {
"image": "<?php echo $item ?: ''; ?>"
}
}<?php if($count != 0): ?>,<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
}7. Running the file containing this code (phpcode.php) directly converts the result into a JSON structure, which meets expectations. As shown in Figure 4.

{
"slide-0": {
"type": "slide",
"settings": {
"image": "1"
}
}, "slide-1": {
"type": "slide",
"settings": {
"image": "2"
}
}, "slide-2": {
"type": "slide",
"settings": {
"image": "3"
}
} }
8. Now I need to create a new PHP script, and then use output buffering to include the PHP file into a string. Reference: https://www.php.net/manual/zh/function.include.php . I created a new PHP file ob.php, and after running it, it outputs a JSON structure, which meets expectations. As shown in Figure 5.

<?php
$string = get_include_contents('phpcode.php');
echo $string;
function get_include_contents($filename) {
if (is_file($filename)) {
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
return false;
}9. However, because the front-end colleagues felt that this approach of adjusting the template to native PHP syntax had poor readability and required too much work, they still required the back-end to automate the entire process, including the compilation of Blade into PHP templates. The final implemented solution is as follows.
/*
$filename = $directory . '/' . substr($themeAsset->asset_key, 6);
if (Storage::disk('local')->exists($filename)) {
ob_start();
include storage_path('app') . '/' . $filename;
$contents = ob_get_contents();
ob_end_clean();
$themeAsset->schema = $contents;
$themeAsset->save();
}
*/
View::addLocation(storage_path('app') . '/' . $directory);
$filename = substr(substr($originalThemeAsset->asset_key, 0, strpos($originalThemeAsset->asset_key, '.')), 6);
$variables = $this->getBladeSchemaCompilerVariables($filename, $originalThemeInstallation->theme);
$schema = View::make($filename)->with($variables)->render();
$themeAsset->schema = $schema;
$themeAsset->save();
