@@ -58,6 +58,18 @@ public function setCategoryIds($ids)
5858 $ ids = [(int )$ ids ];
5959 }
6060 $ this ->_selectedIds = $ ids ;
61+
62+ // Pre-compute expanded paths for all selected categories so that
63+ // ancestors are marked as expanded before the JSON is generated.
64+ $ this ->_expandedPath = [];
65+ if (!empty ($ ids )) {
66+ $ collection = $ this ->_categoryFactory ->create ()->getCollection ();
67+ $ collection ->addAttributeToSelect ('path ' )
68+ ->addAttributeToFilter ('entity_id ' , ['in ' => $ ids ]);
69+ foreach ($ collection as $ category ) {
70+ $ this ->setExpandedPath ($ category ->getPath ());
71+ }
72+ }
6173 return $ this ;
6274 }
6375
@@ -122,4 +134,73 @@ protected function _getNodeJson($node, $level = 1)
122134 $ item ['expanded ' ] = in_array ($ node ->getId (), $ this ->getExpandedPath ());
123135 return $ item ;
124136 }
137+
138+ /**
139+ * Get tree structure
140+ *
141+ * Ensure that deeply selected categories are present by building the tree
142+ * around selected IDs rather than the default 3-level root-only tree.
143+ *
144+ * @param mixed|null $parenNodeCategory
145+ * @return array
146+ */
147+ public function getTree ($ parenNodeCategory = null )
148+ {
149+ // For AJAX child loads, respect the requested parent node
150+ if ($ parenNodeCategory !== null ) {
151+ $ root = $ this ->getRoot ($ parenNodeCategory );
152+ } else {
153+ $ root = empty ($ this ->_selectedIds )
154+ ? $ this ->getRoot ($ parenNodeCategory )
155+ : $ this ->getRootByIds ($ this ->_selectedIds );
156+ }
157+
158+ $ rootArray = $ this ->_getNodeJson ($ root );
159+ return $ rootArray ['children ' ] ?? [];
160+ }
161+
162+ /**
163+ * Get tree json
164+ *
165+ * Ensure that deeply selected categories are present in the JSON output.
166+ *
167+ * @param mixed|null $parenNodeCategory
168+ * @return string
169+ */
170+ public function getTreeJson ($ parenNodeCategory = null )
171+ {
172+ // For AJAX child loads, respect the requested parent node
173+ if ($ parenNodeCategory !== null ) {
174+ $ root = $ this ->getRoot ($ parenNodeCategory );
175+ } else {
176+ $ root = empty ($ this ->_selectedIds )
177+ ? $ this ->getRoot ($ parenNodeCategory )
178+ : $ this ->getRootByIds ($ this ->_selectedIds );
179+ }
180+
181+ $ rootArray = $ this ->_getNodeJson ($ root );
182+ return $ this ->_jsonEncoder ->encode ($ rootArray ['children ' ] ?? []);
183+ }
184+
185+ /**
186+ * Override parent's implementation to avoid using cached registry root
187+ *
188+ * @param array $ids
189+ * @return \Magento\Framework\Data\Tree\Node|array|null
190+ */
191+ public function getRootByIds ($ ids )
192+ {
193+ $ ids = $ this ->_categoryTree ->getExistingCategoryIdsBySpecifiedIds ($ ids );
194+ $ tree = $ this ->_categoryTree ->loadByIds ($ ids );
195+ $ rootId = \Magento \Catalog \Model \Category::TREE_ROOT_ID ;
196+ $ root = $ tree ->getNodeById ($ rootId );
197+ if ($ root ) {
198+ $ root ->setIsVisible (true );
199+ if ($ root ->getId () == \Magento \Catalog \Model \Category::TREE_ROOT_ID ) {
200+ $ root ->setName (__ ('Root ' ));
201+ }
202+ }
203+ $ tree ->addCollectionData ($ this ->getCategoryCollection ());
204+ return $ root ;
205+ }
125206}
0 commit comments