Skip to content

Commit 153bbfd

Browse files
committed
feat(UVE): Implement Universal Visual Editor support for rows, columns, and containers
- Added data attributes for UVE in row, column, and container templates. - Enhanced error handling for missing data in templates. - Included detailed instructions for UVE implementation in the guide.
1 parent 28a0ccb commit 153bbfd

1 file changed

Lines changed: 174 additions & 2 deletions

File tree

instructions/guide.md

Lines changed: 174 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,12 @@ if (!isset($row)) {
530530
return;
531531
}
532532

533-
$rowStyleClass = isset($row['styleClass']) ? ' ' . htmlspecialchars($row['styleClass']) : '';
533+
$rowStyleClass = isset($row->styleClass) ? ' ' . htmlspecialchars($row->styleClass) : '';
534534
?>
535535
<div class="container">
536-
<div class="row<?= $rowStyleClass ?>">
536+
<div class="row<?= $rowStyleClass ?>"
537+
data-dot-object="row"
538+
data-dot-layout-row>
537539
<?php
538540
if (isset($row->columns) && is_array($row->columns)) {
539541
foreach ($row->columns as $column) {
@@ -665,6 +667,176 @@ The /dA/ path is dotCMS's image API for delivery image with top performance.
665667

666668
Create similar templates for other content types based on their fields.
667669

670+
## Step 18: Implementing Universal Visual Editor Support
671+
672+
The Universal Visual Editor (UVE) in dotCMS requires specific data attributes to enable in-context editing. We'll implement these attributes in a top-down approach: rows, columns, containers, and contentlets.
673+
674+
### Step 18.1: Adding UVE Support for Rows
675+
676+
Update `templates/partials/row.php` to include UVE data attributes:
677+
678+
```php
679+
<?php
680+
if (!isset($row)) {
681+
echo "<!-- Error: Row data missing -->";
682+
return;
683+
}
684+
685+
$rowStyleClass = isset($row->styleClass) ? ' ' . htmlspecialchars($row->styleClass) : '';
686+
?>
687+
<div class="container">
688+
<div
689+
data-dot-object="row"
690+
class="row<?= $rowStyleClass ?>"
691+
>
692+
<?php
693+
if (isset($row->columns) && is_array($row->columns)) {
694+
foreach ($row->columns as $column) {
695+
include __DIR__ . '/column.php';
696+
}
697+
} else {
698+
echo "<!-- No Columns found in this Row -->";
699+
}
700+
?>
701+
</div>
702+
</div>
703+
```
704+
705+
The `data-dot-object="row"` attribute identifies this element as a row in the UVE.
706+
707+
### Step 18.2: Adding UVE Support for Columns
708+
709+
Update `templates/partials/column.php` to include UVE data attributes:
710+
711+
```php
712+
<?php
713+
if (!isset($column)) {
714+
echo "<!-- Error: Column data missing -->";
715+
return;
716+
}
717+
718+
// Calculate grid classes based on dotCMS layout properties
719+
$leftOffset = $column->leftOffset ?? 1;
720+
$width = $column->width ?? 12;
721+
$columnClasses = 'col-start-' . $leftOffset . ' col-end-' . ($width + $leftOffset);
722+
723+
if (isset($column->styleClass)) {
724+
$columnClasses .= ' ' . htmlspecialchars($column->styleClass);
725+
}
726+
?>
727+
<div
728+
data-dot-object="column"
729+
class="<?= $columnClasses ?>"
730+
>
731+
<?php
732+
if (isset($column->containers) && is_array($column->containers)) {
733+
foreach ($column->containers as $containerRef) {
734+
include __DIR__ . '/container.php';
735+
}
736+
} else {
737+
echo "<!-- No Containers found in this Column -->";
738+
}
739+
?>
740+
</div>
741+
```
742+
743+
The `data-dot-object="column"` attribute identifies this element as a column in the UVE.
744+
745+
### Step 18.3: Adding UVE Support for Containers and Contentlets
746+
747+
Update `templates/partials/container.php` to include UVE data attributes for both containers and contentlets:
748+
749+
```php
750+
<?php
751+
if (!isset($containerRef)) {
752+
echo "<!-- Error: Container identifier missing -->";
753+
return;
754+
}
755+
756+
global $pageAsset;
757+
758+
$identifier = $containerRef->identifier ?? null;
759+
$uuid = $containerRef->uuid ?? null;
760+
$container = $pageAsset->containers[$identifier] ?? null;
761+
762+
// Container attributes for UVE
763+
$containerAttrs = [
764+
'data-dot-object' => 'container',
765+
'data-dot-identifier' => $identifier,
766+
'data-dot-uuid' => $uuid,
767+
'data-dot-accept-types' => $container->acceptTypes ?? '',
768+
'data-max-contentlets' => $container->maxContentlets ?? 0
769+
];
770+
771+
// Build HTML attributes string
772+
$htmlAttrs = '';
773+
foreach ($containerAttrs as $attr => $value) {
774+
if ($value !== null && $value !== '') {
775+
$htmlAttrs .= ' ' . $attr . '="' . htmlspecialchars($value) . '"';
776+
}
777+
}
778+
?>
779+
<div<?= $htmlAttrs ?>>
780+
<?php
781+
// Note: dotCMS stores contentlets with a "uuid-" prefix in lowercase
782+
$contentlets = $pageAsset->containers[$identifier]->contentlets[strtolower("uuid-" . $uuid)] ?? null;
783+
784+
if ($contentlets) {
785+
foreach ($contentlets as $contentlet) {
786+
// Contentlet attributes for UVE
787+
$contentletAttrs = [
788+
'data-dot-object' => 'contentlet',
789+
'data-dot-identifier' => $contentlet->identifier ?? '',
790+
'data-dot-inode' => $contentlet->inode ?? '',
791+
'data-dot-type' => $contentlet->contentType ?? '',
792+
'data-dot-basetype' => $contentlet->baseType ?? '',
793+
'data-dot-title' => $contentlet->title ?? '',
794+
'data-dot-container' => json_encode([
795+
'identifier' => $identifier,
796+
'uuid' => $uuid,
797+
'acceptTypes' => $container->acceptTypes ?? [],
798+
'maxContentlets' => $container->maxContentlets ?? 0,
799+
'variantId' => $containerRef->variantId ?? null
800+
])
801+
];
802+
803+
// Build contentlet HTML attributes string
804+
$contentletHtmlAttrs = '';
805+
foreach ($contentletAttrs as $attr => $value) {
806+
if ($value !== null && $value !== '') {
807+
$contentletHtmlAttrs .= ' ' . $attr . '="' . htmlspecialchars($value) . '"';
808+
}
809+
}
810+
811+
$contentTypeVar = $contentlet->contentType ?? 'unknown';
812+
$templatePath = dirname(__DIR__) . '/content-type/' . strtolower($contentTypeVar) . '.php';
813+
?>
814+
<div<?= $contentletHtmlAttrs ?>>
815+
<?php
816+
if (file_exists($templatePath)) {
817+
include $templatePath;
818+
} else {
819+
include dirname(__DIR__) . '/content-type/content-type-not-found.php';
820+
}
821+
?>
822+
</div>
823+
<?php
824+
}
825+
} else {
826+
echo "<!-- Container $identifier doesn't have contentlets -->";
827+
}
828+
?>
829+
</div>
830+
```
831+
### Important Notes About UVE Implementation
832+
833+
1. **Data Attributes**: All UVE data attributes start with `data-dot-` prefix
834+
2. **Container JSON**: The container data in contentlets must be JSON-encoded
835+
3. **Unique Identifiers**: Make sure all identifiers (uuid, inode) are properly passed
836+
4. **Error Handling**: Always validate data before outputting attributes
837+
5. **Content Type Templates**: Keep content type templates focused on rendering content only
838+
6. **Inheritance**: The UVE attributes follow the same hierarchy as the page structure
839+
668840
## Troubleshooting
669841

670842
### Common Issues

0 commit comments

Comments
 (0)