1919use Magento \Framework \Setup \Patch \DataPatchInterface ;
2020use Magento \Framework \Setup \Patch \PatchRevertableInterface ;
2121use Smile \CustomEntity \Api \Data \CustomEntityAttributeInterface ;
22+ use Amadeco \SmileCustomEntitySeo \Api \Data \CustomEntitySeoInterface ;
2223use Amadeco \SmileCustomEntitySeo \Model \Source \Robots ;
2324
2425/**
2728class AddSeoAttributesAndGroups implements DataPatchInterface, PatchRevertableInterface
2829{
2930 /**
30- * @var string
31+ * SEO attribute group name
3132 */
32- private const ATTRIBUTE_GROUP_SEO_NAME = 'Search Engine Optimization ' ;
33+ public const SEO_GROUP_NAME = 'Search Engine Optimization ' ;
34+
35+ /**
36+ * SEO attribute group sort order
37+ */
38+ public const SEO_GROUP_SORT_ORDER = 100 ;
39+
40+ /**
41+ * SEO attributes configuration
42+ */
43+ private const SEO_ATTRIBUTES = [
44+ CustomEntitySeoInterface::META_TITLE => [
45+ 'type ' => 'varchar ' ,
46+ 'label ' => 'Meta Title ' ,
47+ 'input ' => 'text ' ,
48+ 'required ' => false ,
49+ 'sort_order ' => 10
50+ ],
51+ CustomEntitySeoInterface::META_DESCRIPTION => [
52+ 'type ' => 'text ' ,
53+ 'label ' => 'Meta Description ' ,
54+ 'input ' => 'textarea ' ,
55+ 'required ' => false ,
56+ 'note ' => 'Maximum 255 chars ' ,
57+ 'class ' => 'validate-length maximum-length-255 ' ,
58+ 'sort_order ' => 20
59+ ],
60+ CustomEntitySeoInterface::META_KEYWORDS => [
61+ 'type ' => 'text ' ,
62+ 'label ' => 'Meta Keywords ' ,
63+ 'input ' => 'textarea ' ,
64+ 'required ' => false ,
65+ 'sort_order ' => 30
66+ ],
67+ CustomEntitySeoInterface::META_ROBOTS => [
68+ 'type ' => 'varchar ' ,
69+ 'label ' => 'Meta Robots ' ,
70+ 'input ' => 'select ' ,
71+ 'source ' => Robots::class,
72+ 'required ' => false ,
73+ 'sort_order ' => 40 ,
74+ 'default ' => ''
75+ ]
76+ ];
3377
3478 /**
3579 * @var ModuleDataSetupInterface
@@ -71,91 +115,76 @@ public function apply()
71115 /** @var EavSetup $eavSetup */
72116 $ eavSetup = $ this ->eavSetupFactory ->create (['setup ' => $ this ->moduleDataSetup ]);
73117
74- // Create attribute group if it doesn't exist
118+ $ this ->createSeoAttributeGroups ($ eavSetup );
119+ $ this ->createSeoAttributes ($ eavSetup );
120+
121+ return $ this ;
122+ }
123+
124+ /**
125+ * Create SEO attribute groups in all attribute sets
126+ *
127+ * @param EavSetup $eavSetup
128+ * @return void
129+ */
130+ private function createSeoAttributeGroups (EavSetup $ eavSetup ): void
131+ {
75132 $ entityTypeId = $ eavSetup ->getEntityTypeId (CustomEntityAttributeInterface::ENTITY_TYPE_CODE );
76133 $ attributeSetIds = $ eavSetup ->getAllAttributeSetIds ($ entityTypeId );
77134
78- // Create SEO group in all attribute sets
135+ // Create SEO group in all attribute sets if it doesn't exist
79136 foreach ($ attributeSetIds as $ attributeSetId ) {
80- $ groupId = $ eavSetup ->getAttributeGroupId ($ entityTypeId , $ attributeSetId , self ::ATTRIBUTE_GROUP_SEO_NAME );
137+ $ groupId = $ eavSetup ->getAttributeGroupId ($ entityTypeId , $ attributeSetId , self ::SEO_GROUP_NAME );
81138
82139 if (!$ groupId ) {
83140 $ eavSetup ->addAttributeGroup (
84141 CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
85142 $ attributeSetId ,
86- self ::ATTRIBUTE_GROUP_SEO_NAME ,
87- 100 // Sort order
143+ self ::SEO_GROUP_NAME ,
144+ self :: SEO_GROUP_SORT_ORDER
88145 );
89146 }
90147 }
148+ }
91149
92- // Add meta_title attribute
93- $ eavSetup ->addAttribute (
94- CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
95- 'meta_title ' ,
96- [
97- 'type ' => 'varchar ' ,
98- 'label ' => 'Meta Title ' ,
99- 'input ' => 'text ' ,
100- 'required ' => false ,
101- 'sort_order ' => 10 ,
102- 'global ' => ScopedAttributeInterface::SCOPE_STORE ,
103- 'group ' => self ::ATTRIBUTE_GROUP_SEO_NAME ,
104- 'is_used_in_grid ' => false ,
105- 'is_visible_in_grid ' => false ,
106- 'is_filterable_in_grid ' => false ,
107- 'note ' => 'Maximum 255 characters '
108- ]
109- );
110-
111- // Add meta_description attribute
112- $ eavSetup ->addAttribute (
113- CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
114- 'meta_description ' ,
115- [
116- 'type ' => 'text ' ,
117- 'label ' => 'Meta Description ' ,
118- 'input ' => 'textarea ' ,
119- 'required ' => false ,
120- 'sort_order ' => 20 ,
121- 'global ' => ScopedAttributeInterface::SCOPE_STORE ,
122- 'group ' => self ::ATTRIBUTE_GROUP_SEO_NAME
123- ]
124- );
125-
126- // Add meta_keywords attribute
127- $ eavSetup ->addAttribute (
128- CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
129- 'meta_keywords ' ,
130- [
131- 'type ' => 'text ' ,
132- 'label ' => 'Meta Keywords ' ,
133- 'input ' => 'textarea ' ,
134- 'required ' => false ,
135- 'sort_order ' => 30 ,
136- 'global ' => ScopedAttributeInterface::SCOPE_STORE ,
137- 'group ' => self ::ATTRIBUTE_GROUP_SEO_NAME
138- ]
139- );
140-
141- // Add meta_robots attribute
142- $ eavSetup ->addAttribute (
143- CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
144- 'meta_robots ' ,
145- [
146- 'type ' => 'varchar ' ,
147- 'label ' => 'Meta Robots ' ,
148- 'input ' => 'select ' ,
149- 'source ' => Robots::class,
150- 'required ' => false ,
151- 'sort_order ' => 40 ,
152- 'global ' => ScopedAttributeInterface::SCOPE_STORE ,
153- 'group ' => self ::ATTRIBUTE_GROUP_SEO_NAME ,
154- 'default ' => ''
155- ]
156- );
150+ /**
151+ * Create SEO attributes if they don't exist
152+ *
153+ * @param EavSetup $eavSetup
154+ * @return void
155+ * @throws LocalizedException
156+ */
157+ private function createSeoAttributes (EavSetup $ eavSetup ): void
158+ {
159+ foreach (self ::SEO_ATTRIBUTES as $ attributeCode => $ attributeData ) {
160+ // Check if attribute already exists
161+ try {
162+ $ attribute = $ this ->eavConfig ->getAttribute (
163+ CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
164+ $ attributeCode
165+ );
157166
158- return $ this ;
167+ if ($ attribute && $ attribute ->getId ()) {
168+ // Attribute already exists, skip creation
169+ continue ;
170+ }
171+ } catch (\Exception $ e ) {
172+ // Attribute doesn't exist, we can create it
173+ }
174+
175+ // Add common attribute properties
176+ $ attributeData = array_merge ($ attributeData , [
177+ 'global ' => ScopedAttributeInterface::SCOPE_STORE ,
178+ 'group ' => self ::SEO_GROUP_NAME
179+ ]);
180+
181+ // Create attribute
182+ $ eavSetup ->addAttribute (
183+ CustomEntityAttributeInterface::ENTITY_TYPE_CODE ,
184+ $ attributeCode ,
185+ $ attributeData
186+ );
187+ }
159188 }
160189
161190 /**
@@ -167,10 +196,9 @@ public function revert()
167196 $ eavSetup = $ this ->eavSetupFactory ->create (['setup ' => $ this ->moduleDataSetup ]);
168197
169198 // Remove attributes
170- $ eavSetup ->removeAttribute (CustomEntityAttributeInterface::ENTITY_TYPE_CODE , 'meta_title ' );
171- $ eavSetup ->removeAttribute (CustomEntityAttributeInterface::ENTITY_TYPE_CODE , 'meta_description ' );
172- $ eavSetup ->removeAttribute (CustomEntityAttributeInterface::ENTITY_TYPE_CODE , 'meta_keywords ' );
173- $ eavSetup ->removeAttribute (CustomEntityAttributeInterface::ENTITY_TYPE_CODE , 'meta_robots ' );
199+ foreach (array_keys (self ::SEO_ATTRIBUTES ) as $ attributeCode ) {
200+ $ eavSetup ->removeAttribute (CustomEntityAttributeInterface::ENTITY_TYPE_CODE , $ attributeCode );
201+ }
174202
175203 return $ this ;
176204 }
0 commit comments