Skip to content

Commit 1039ec8

Browse files
committed
feat: add lazy tree expansion for selective block rendering
1 parent 41f1334 commit 1039ec8

File tree

3 files changed

+102
-38
lines changed

3 files changed

+102
-38
lines changed

src/Http/Controllers/Admin/ThemeEditorController.php

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,9 @@ public function persistUpdates(Request $request)
8787
'updates.regions' => ['present', 'array'],
8888
]);
8989

90-
$result = $this->persistEditorUpdates->handle($validated);
91-
$loadedBlocks = $result['loadedBlocks'] ?? [];
90+
$this->persistEditorUpdates->handle($validated);
9291

93-
$changedBlockIds = $this->extractChangedBlockIds(
94-
$validated['updates'],
95-
$loadedBlocks
96-
);
92+
$changedBlockIds = $this->extractChangedBlockIds($validated['updates']);
9793

9894
$url = $request->input('template.url');
9995

@@ -370,36 +366,16 @@ protected function getVisualThemes(): array
370366
}
371367

372368
/**
373-
* Extract changed block IDs from updates and include all parent blocks.
369+
* Extract changed block IDs from updates.
370+
* Tree expansion (parents + children) happens during render via BlockRenderFilter.
374371
*/
375-
protected function extractChangedBlockIds(array $updates, array $loadedBlocks): array
372+
protected function extractChangedBlockIds(array $updates): array
376373
{
377374
$changes = $updates['changes'] ?? [];
378375

379-
$changedIds = array_merge($changes['added'] ?? [], $changes['updated'] ?? []);
380-
381-
return $this->includeParentBlocks($changedIds, $loadedBlocks);
382-
}
383-
384-
/**
385-
* Include all parent blocks for the given block IDs.
386-
*/
387-
protected function includeParentBlocks(array $blockIds, array $loadedBlocks): array
388-
{
389-
$result = [];
390-
391-
foreach ($blockIds as $id) {
392-
$result[] = $id;
393-
394-
// Walk up the parent chain using parentId
395-
$currentId = $id;
396-
while (isset($loadedBlocks[$currentId]['parentId']) && $loadedBlocks[$currentId]['parentId'] !== null) {
397-
$parentId = $loadedBlocks[$currentId]['parentId'];
398-
$result[] = $parentId;
399-
$currentId = $parentId;
400-
}
401-
}
402-
403-
return array_unique($result);
376+
return array_merge(
377+
$changes['added'] ?? [],
378+
$changes['updated'] ?? []
379+
);
404380
}
405381
}

src/Providers/CoreServiceProvider.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use BagistoPlus\Visual\Middlewares\DisableResponseCacheInDesignMode;
1111
use BagistoPlus\Visual\Middlewares\UseShopThemeFromRequest;
1212
use BagistoPlus\Visual\Settings\Support as SettingTransformers;
13+
use BagistoPlus\Visual\Support\BlockRenderFilter;
1314
use BagistoPlus\Visual\Support\UrlGenerator;
1415
use BagistoPlus\Visual\TemplateRegistrar;
1516
use BagistoPlus\Visual\ThemePathsResolver;
@@ -105,13 +106,13 @@ protected function bootCraftile(): void
105106
Craftile::normalizeTemplateUsing(new \BagistoPlus\Visual\Support\TemplateNormalizer);
106107

107108
Craftile::checkIfBlockCanRenderUsing(function (BlockData $blockData) {
108-
if (ThemeEditor::inDesignMode() && request()->has('_blocks')) {
109-
$blocksToRender = explode(',', request()->query('_blocks'));
110-
111-
return in_array($blockData->id, $blocksToRender);
109+
if (! ThemeEditor::inDesignMode() || ! request()->has('_blocks')) {
110+
return ! $blockData->disabled;
112111
}
113112

114-
return ! $blockData->disabled;
113+
$filter = app(BlockRenderFilter::class);
114+
115+
return $filter->shouldRender($blockData);
115116
});
116117

117118
$this->registerPropertyTransformers();
@@ -252,6 +253,9 @@ protected function registerSingletons(): void
252253
$app->get('files')
253254
);
254255
});
256+
257+
// Register BlockRenderFilter as singleton for request-scoped caching
258+
$this->app->singleton(BlockRenderFilter::class);
255259
}
256260

257261
protected function registerCustomUrlGenerator(): void

src/Support/BlockRenderFilter.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace BagistoPlus\Visual\Support;
4+
5+
use BagistoPlus\Visual\Data\BlockData;
6+
use Craftile\Laravel\Facades\BlockDatastore;
7+
8+
class BlockRenderFilter
9+
{
10+
protected ?array $renderSet = null;
11+
12+
protected array $processed = [];
13+
14+
/**
15+
* Check if a block should be rendered based on the _blocks query parameter.
16+
*/
17+
public function shouldRender(BlockData $blockData): bool
18+
{
19+
if ($this->renderSet === null) {
20+
$this->buildRenderSet();
21+
}
22+
23+
return isset($this->renderSet[$blockData->id]);
24+
}
25+
26+
/**
27+
* Build the set of blocks to render from query parameter.
28+
*/
29+
protected function buildRenderSet(): void
30+
{
31+
$changedBlocks = explode(',', request()->query('_blocks', ''));
32+
$this->renderSet = array_flip($changedBlocks);
33+
34+
foreach ($changedBlocks as $blockId) {
35+
$this->expandBlockTree($blockId);
36+
}
37+
}
38+
39+
/**
40+
* Recursively expand block tree to include all parents and children.
41+
*/
42+
protected function expandBlockTree(string $blockId): void
43+
{
44+
if (isset($this->processed[$blockId])) {
45+
return;
46+
}
47+
48+
$this->processed[$blockId] = true;
49+
50+
try {
51+
$blockData = BlockDatastore::getBlock($blockId);
52+
53+
if (! $blockData) {
54+
return;
55+
}
56+
57+
$this->renderSet[$blockData->id] = true;
58+
59+
// Walk up: include all parents
60+
if ($blockData->parentId) {
61+
$this->expandBlockTree($blockData->parentId);
62+
}
63+
64+
// Walk down: include all children
65+
if ($blockData->hasChildren()) {
66+
foreach ($blockData->childrenIds() as $childId) {
67+
$this->expandBlockTree($childId);
68+
}
69+
}
70+
} catch (\Exception $e) {
71+
// Block not found or error - skip silently
72+
return;
73+
}
74+
}
75+
76+
/**
77+
* Reset the filter state (useful for testing).
78+
*/
79+
public function reset(): void
80+
{
81+
$this->renderSet = null;
82+
$this->processed = [];
83+
}
84+
}

0 commit comments

Comments
 (0)