@@ -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
666668Create 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