From fda80d262d1ca8005ece933c6d03525037970569 Mon Sep 17 00:00:00 2001
From: Amandeep Singh <arshgrover32@gmail.com>
Date: Thu, 2 Jan 2025 15:56:38 +0530
Subject: [PATCH 1/6] Add SEO settings section to page data form.

---
 experience_builder.module                     | 27 +++++++++++++++++++
 .../Entity/PageMetatagIntegrationTest.php     | 18 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/experience_builder.module b/experience_builder.module
index 098d8412b5..8cfef04b25 100644
--- a/experience_builder.module
+++ b/experience_builder.module
@@ -404,3 +404,30 @@ function experience_builder_form_system_theme_settings_submit(array &$form, Form
   $form_state->unsetValue('use_xb');
   $form_state->unsetValue('editable');
 }
+
+/**
+ * Implements hook_form_BASE_FORM_ID_alter().
+ *
+ * Alters XB page form to group meta related fields.
+ */
+function experience_builder_form_xb_page_form_alter(array &$form, FormStateInterface $form_state): void {
+  $group = 'seo_settings';
+  $form[$group] = [
+    '#type' => 'details',
+    '#group' => 'advanced',
+    '#weight' => -10,
+    '#title' => t('SEO settings'),
+    '#tree' => TRUE,
+    // Not keeping it open messes up media library ajax.
+    '#open' => TRUE,
+  ];
+  $form[$group]['image'] = $form['image'];
+  $form[$group]['image']['#weight'] = -10;
+  unset($form['image']);
+  $form[$group]['description'] = $form['description'];
+  $form[$group]['description']['#weight'] = 10;
+  unset($form['description']);
+  if (isset($form['metatags']['widget'][0]['basic']['title'])) {
+    $form['metatags']['widget'][0]['basic']['title']['#group'] = $group;
+  }
+}
diff --git a/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php b/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
index 7af2101199..edac99be54 100644
--- a/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
+++ b/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\Tests\experience_builder\Kernel\Entity;
 
+use Drupal\experience_builder\Controller\EntityFormController;
 use Drupal\experience_builder\Entity\Page;
 use Drupal\file\Entity\File;
 use Drupal\KernelTests\KernelTestBase;
@@ -141,4 +142,21 @@ final class PageMetatagIntegrationTest extends KernelTestBase {
     self::assertEquals($expected, $metatags['#attached']['html_head']);
   }
 
+  public function testSeoSettingsForm(): void {
+    $this->container->get('module_installer')->install(['metatag']);
+    $page = Page::create([
+      'title' => 'Test page',
+      'description' => 'This is a test page.',
+      'path' => ['alias' => '/test-page'],
+      'components' => [],
+    ]);
+    self::assertSaveWithoutViolations($page);
+    $sut = new EntityFormController();
+    $form = $sut->form('xb_page', $page, 'default');
+    $seo_settings = ($form['seo_settings']);
+    self::assertArrayHasKey('image', $seo_settings);
+    self::assertArrayHasKey('description', $seo_settings);
+    self::assertEquals('seo_settings', $form['metatags']['widget'][0]['basic']['title']['#group']);
+  }
+
 }
-- 
GitLab


From 7d8687b33a921be001a22c04c4bb9f0807b199af Mon Sep 17 00:00:00 2001
From: Amandeep Singh <arshgrover32@gmail.com>
Date: Mon, 6 Jan 2025 16:36:48 +0530
Subject: [PATCH 2/6] Create explicit form for xb_page.

---
 experience_builder.module                     | 27 ------------
 src/Entity/Page.php                           |  2 +-
 src/Entity/XbPageForm.php                     | 43 +++++++++++++++++++
 .../Entity/PageMetatagIntegrationTest.php     |  5 +--
 4 files changed, 46 insertions(+), 31 deletions(-)
 create mode 100644 src/Entity/XbPageForm.php

diff --git a/experience_builder.module b/experience_builder.module
index 8cfef04b25..098d8412b5 100644
--- a/experience_builder.module
+++ b/experience_builder.module
@@ -404,30 +404,3 @@ function experience_builder_form_system_theme_settings_submit(array &$form, Form
   $form_state->unsetValue('use_xb');
   $form_state->unsetValue('editable');
 }
-
-/**
- * Implements hook_form_BASE_FORM_ID_alter().
- *
- * Alters XB page form to group meta related fields.
- */
-function experience_builder_form_xb_page_form_alter(array &$form, FormStateInterface $form_state): void {
-  $group = 'seo_settings';
-  $form[$group] = [
-    '#type' => 'details',
-    '#group' => 'advanced',
-    '#weight' => -10,
-    '#title' => t('SEO settings'),
-    '#tree' => TRUE,
-    // Not keeping it open messes up media library ajax.
-    '#open' => TRUE,
-  ];
-  $form[$group]['image'] = $form['image'];
-  $form[$group]['image']['#weight'] = -10;
-  unset($form['image']);
-  $form[$group]['description'] = $form['description'];
-  $form[$group]['description']['#weight'] = 10;
-  unset($form['description']);
-  if (isset($form['metatags']['widget'][0]['basic']['title'])) {
-    $form['metatags']['widget'][0]['basic']['title']['#group'] = $group;
-  }
-}
diff --git a/src/Entity/Page.php b/src/Entity/Page.php
index 4338458658..d7eeca3a0f 100644
--- a/src/Entity/Page.php
+++ b/src/Entity/Page.php
@@ -36,7 +36,7 @@ use Drupal\user\EntityOwnerTrait;
  *     "view_builder" = "Drupal\experience_builder\Entity\PageViewBuilder",
  *     "views_data" = "Drupal\Core\Entity\EntityViewsData",
  *     "form" = {
- *       "default" = "Drupal\Core\Entity\ContentEntityForm",
+ *       "default" = "Drupal\experience_builder\Entity\XbPageForm",
  *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
  *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
  *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
diff --git a/src/Entity/XbPageForm.php b/src/Entity/XbPageForm.php
new file mode 100644
index 0000000000..abec6c7436
--- /dev/null
+++ b/src/Entity/XbPageForm.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\experience_builder\Entity;
+
+use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Form controller for the XbPage entity forms.
+ *
+ * Overrides the default form to add SEO settings and other customizations.
+ */
+class XbPageForm extends ContentEntityForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state): array {
+    $form = parent::form($form, $form_state);
+    $group = 'seo_settings';
+    $form[$group] = [
+      '#type' => 'details',
+      '#group' => 'advanced',
+      '#weight' => -10,
+      '#title' => t('SEO settings'),
+      '#tree' => TRUE,
+      // Not keeping it open messes up media library ajax
+      // when rendering the form in XB UI.
+      '#open' => TRUE,
+    ];
+    $form[$group]['image'] = $form['image'];
+    $form[$group]['image']['#weight'] = -10;
+    unset($form['image']);
+    $form[$group]['description'] = $form['description'];
+    $form[$group]['description']['#weight'] = 10;
+    unset($form['description']);
+    if (isset($form['metatags']['widget'][0]['basic']['title'])) {
+      $form['metatags']['widget'][0]['basic']['title']['#group'] = $group;
+    }
+    return $form;
+  }
+
+}
diff --git a/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php b/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
index edac99be54..03e0edee9d 100644
--- a/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
+++ b/tests/src/Kernel/Entity/PageMetatagIntegrationTest.php
@@ -153,9 +153,8 @@ final class PageMetatagIntegrationTest extends KernelTestBase {
     self::assertSaveWithoutViolations($page);
     $sut = new EntityFormController();
     $form = $sut->form('xb_page', $page, 'default');
-    $seo_settings = ($form['seo_settings']);
-    self::assertArrayHasKey('image', $seo_settings);
-    self::assertArrayHasKey('description', $seo_settings);
+    self::assertArrayHasKey('image', $form['seo_settings']);
+    self::assertArrayHasKey('description', $form['seo_settings']);
     self::assertEquals('seo_settings', $form['metatags']['widget'][0]['basic']['title']['#group']);
   }
 
-- 
GitLab


From 5aada8000bd482c1cacf8b158028b3db57713e3d Mon Sep 17 00:00:00 2001
From: Amandeep Singh <arshgrover32@gmail.com>
Date: Fri, 10 Jan 2025 17:05:11 +0530
Subject: [PATCH 3/6] Add e2e test confirming the new seo section.

---
 ui/tests/e2e/empty-canvas.cy.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ui/tests/e2e/empty-canvas.cy.js b/ui/tests/e2e/empty-canvas.cy.js
index 760b5446cb..aff364c4ad 100644
--- a/ui/tests/e2e/empty-canvas.cy.js
+++ b/ui/tests/e2e/empty-canvas.cy.js
@@ -4,6 +4,7 @@ describe('Empty canvas', () => {
     // demonstrated to be the only reliable way to get tests after the first
     // passing consistently. This occurs regardless of which test runs first.
     cy.drupalXbInstall();
+    cy.drupalInstallModule('metatag', true);
     cy.drupalLogin('xbUser', 'xbUser');
   });
 
@@ -65,6 +66,11 @@ describe('Empty canvas', () => {
     // Wait for an element in the page data panel to be present.
     cy.get('#edit-title-0-value').should('exist');
 
+    cy.get('#edit-seo-settings').should('exist');
+    cy.get('#edit-seo-settings #edit-image-wrapper').should('exist');
+    cy.get('#edit-seo-settings #edit-metatags-0-basic-title').should('exist');
+    cy.get('#edit-seo-settings #edit-description-wrapper').should('exist');
+
     // Confirm there is nothing in the canvas.
     cy.get('.xb--viewport-overlay [data-xb-component-id]').should('not.exist');
 
-- 
GitLab


From 906bc958bce2fff099d05d5306e191c02046250c Mon Sep 17 00:00:00 2001
From: Amandeep Singh <arshgrover32@gmail.com>
Date: Wed, 15 Jan 2025 13:29:30 +0530
Subject: [PATCH 4/6] MR comments.

---
 src/Entity/XbPageForm.php | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/Entity/XbPageForm.php b/src/Entity/XbPageForm.php
index abec6c7436..a5b2ff4bee 100644
--- a/src/Entity/XbPageForm.php
+++ b/src/Entity/XbPageForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\experience_builder\Entity;
 
 use Drupal\Core\Entity\ContentEntityForm;
@@ -10,7 +12,7 @@ use Drupal\Core\Form\FormStateInterface;
  *
  * Overrides the default form to add SEO settings and other customizations.
  */
-class XbPageForm extends ContentEntityForm {
+final class XbPageForm extends ContentEntityForm {
 
   /**
    * {@inheritdoc}
@@ -22,7 +24,7 @@ class XbPageForm extends ContentEntityForm {
       '#type' => 'details',
       '#group' => 'advanced',
       '#weight' => -10,
-      '#title' => t('SEO settings'),
+      '#title' => $this->t('SEO settings'),
       '#tree' => TRUE,
       // Not keeping it open messes up media library ajax
       // when rendering the form in XB UI.
-- 
GitLab


From a4c9b17d530efbbd37837b5ec8a91364e046f27b Mon Sep 17 00:00:00 2001
From: Amandeep Singh <arshgrover32@gmail.com>
Date: Thu, 23 Jan 2025 11:46:39 +0530
Subject: [PATCH 5/6] Add todo for the issue.

---
 src/Entity/XbPageForm.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/Entity/XbPageForm.php b/src/Entity/XbPageForm.php
index a5b2ff4bee..4f5d1dcffc 100644
--- a/src/Entity/XbPageForm.php
+++ b/src/Entity/XbPageForm.php
@@ -28,6 +28,7 @@ final class XbPageForm extends ContentEntityForm {
       '#tree' => TRUE,
       // Not keeping it open messes up media library ajax
       // when rendering the form in XB UI.
+      // @todo remove this once https://www.drupal.org/project/experience_builder/issues/3501626 lands.
       '#open' => TRUE,
     ];
     $form[$group]['image'] = $form['image'];
-- 
GitLab


From 8457c0204c888a86a43db8dbdf6259e66e4cc24e Mon Sep 17 00:00:00 2001
From: Wim Leers <wim.leers@acquia.com>
Date: Fri, 24 Jan 2025 13:38:47 +0100
Subject: [PATCH 6/6] =?UTF-8?q?Add=20comment=20to=20capture=20the=20Form?=
 =?UTF-8?q?=20API=20`#group`=20bugginess=20that=20@bnjmnm=20uncovered=20?=
 =?UTF-8?q?=F0=9F=98=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/Entity/XbPageForm.php | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/Entity/XbPageForm.php b/src/Entity/XbPageForm.php
index 4f5d1dcffc..9455dc2b24 100644
--- a/src/Entity/XbPageForm.php
+++ b/src/Entity/XbPageForm.php
@@ -33,6 +33,8 @@ final class XbPageForm extends ContentEntityForm {
     ];
     $form[$group]['image'] = $form['image'];
     $form[$group]['image']['#weight'] = -10;
+    // TRICKY: it seems there's a Drupal core bug wrt #group, long-term fix TBD.
+    // @see https://git.drupalcode.org/project/experience_builder/-/merge_requests/501#note_448716
     unset($form['image']);
     $form[$group]['description'] = $form['description'];
     $form[$group]['description']['#weight'] = 10;
-- 
GitLab