Skip to content

Commit

Permalink
Fix nodes not propagating, or being re-saved when enabling a new site…
Browse files Browse the repository at this point in the history
… for a navigation
  • Loading branch information
engram-design committed Jun 20, 2021
1 parent 3e957bf commit fd8a7d6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 46 deletions.
3 changes: 0 additions & 3 deletions src/Navigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,6 @@ private function _registerCraftEventListeners()
// Allow elements to update our nodes
Event::on(Elements::class, Elements::EVENT_BEFORE_SAVE_ELEMENT, [$this->getNodes(), 'onSaveElement']);
Event::on(Elements::class, Elements::EVENT_AFTER_DELETE_ELEMENT, [$this->getNodes(), 'onDeleteElement']);

// When a site is updated, propagate nodes
Event::on(Sites::class, Sites::EVENT_AFTER_SAVE_SITE, [$this->getNodes(), 'afterSaveSiteHandler']);
}

private function _registerProjectConfigEventListeners()
Expand Down
74 changes: 66 additions & 8 deletions src/services/Navs.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use craft\helpers\Json;
use craft\helpers\StringHelper;
use craft\models\Structure;
use craft\queue\jobs\ResaveElements;

use yii\web\UserEvent;

Expand Down Expand Up @@ -270,11 +271,13 @@ public function handleChangedNav(ConfigEvent $event)

// Have we changed the propagation method?
if ($oldRecord->propagateNodes !== $navRecord->propagateNodes) {
$elementsService = Craft::$app->getElements();
$nodesToDelete = [];

// If we've turned off propagating, we need to propagate nodes
if (!$navRecord->propagateNodes && $oldRecord->propagateNodes) {
$primarySiteId = Craft::$app->getSites()->getPrimarySite()->id;
$nav = $this->getNavById($navRecord->id);
$elementsService = Craft::$app->getElements();

$nodes = Node::find()
->navId($navRecord->id)
Expand All @@ -284,26 +287,51 @@ public function handleChangedNav(ConfigEvent $event)
->all();

foreach ($nav->getEditableSites() as $site) {
// No need to re-save the primary site, it's all good as-is
if ($site->id == $primarySiteId) {
continue;
}

// If we try and propagate nodes to another site's nav, which already
// has nodes, we'll get duplicates. As there's no real way to compare
// propagated and non-propagated nodes (effectively), we need to wipe all
// other enabled nav nodes first, before duplicating.
$existingNodes = Node::find()->siteId($site->id)->all();

// But, we need to wait for all navigations to finish, before deleting.
// Otherwise, we'll delete a node in one site navigation, and because we've
// set to propagate, it'll delete it from all other navs instantly.
foreach ($existingNodes as $existingNode) {
$elementsService->deleteElement($existingNode);
$nodesToDelete[] = $existingNode;
}

$this->_duplicateElements($nodes, ['siteId' => $site->id]);
}
} else {
// Do nothing for now, until we figure out the best way to handle it...
}

foreach ($nodesToDelete as $nodeToDelete) {
$elementsService->deleteElement($nodeToDelete);
}
}

// When enabling/disabling sites
if (Craft::$app->getIsMultiSite()) {
// Has the sites been changed?
$oldSiteSettings = Json::decode($oldRecord->siteSettings);
$newSiteSettings = Json::decode($navRecord->siteSettings);

// Removed sites
foreach ($oldSiteSettings as $key => $value) {
if (!isset($newSiteSettings[$key])) {
// Nothing for now
}
}

// Added sites
foreach ($newSiteSettings as $key => $value) {
if (!isset($oldSiteSettings[$key])) {
$siteId = Db::idByUid(Table::SITES, $key);

$this->resaveNodesForSite($navRecord, $siteId);
}
}
}

// Fire an 'afterSaveNav' event
Expand Down Expand Up @@ -482,6 +510,37 @@ public function getBuilderTabs($nav)
return $tabs;
}

public function resaveNodesForSite($nav, $siteId)
{
$primarySiteId = Craft::$app->getSites()->getPrimarySite()->id;

// Only propagate nodes if we want to for the nav
if ($nav->propagateNodes) {
$nodes = [];

foreach (Node::find()->navId($nav->id)->siteId($primarySiteId)->all() as $node) {
$nodes[] = $node->id;
}

Craft::$app->getQueue()->push(new ResaveElements([
'elementType' => Node::class,
'criteria' => [
'id' => $nodes,
]
]));
} else {
// Duplicate existing elements
$nodes = Node::find()
->navId($nav->id)
->siteId($primarySiteId)
->level(1)
->orderBy(['structureelements.lft' => SORT_ASC])
->all();

$this->_duplicateElements($nodes, ['siteId' => $siteId]);
}
}


// Private Methods
// =========================================================================
Expand Down Expand Up @@ -549,5 +608,4 @@ private function _duplicateElements($elements, $newAttributes = [], &$duplicated
$this->_duplicateElements($children, $newAttributes, $duplicatedElementIds, $duplicate);
}
}

}
35 changes: 0 additions & 35 deletions src/services/Nodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use craft\base\Component;
use craft\events\ElementEvent;
use craft\events\SiteEvent;
use craft\queue\jobs\ResaveElements;

use verbb\navigation\Navigation;
use verbb\navigation\elements\Node as NodeElement;
Expand Down Expand Up @@ -125,38 +124,4 @@ public function getParentOptions($nodes, $nav)

return $parentOptions;
}

public function afterSaveSiteHandler(SiteEvent $event)
{
$queue = Craft::$app->getQueue();
$siteId = $event->site->id;

// Only propagate nodes if we want to for the nav
$navs = Navigation::$plugin->getNavs()->getAllNavs();
$nodes = [];

foreach ($navs as $nav) {
if ($nav->propagateNodes) {
foreach (Navigation::$plugin->getNodes()->getNodesForNav($nav->id) as $node) {
$nodes[] = $node->id;
}
}
}

$elementTypes = [
NodeElement::class,
];

foreach ($elementTypes as $elementType) {
$queue->push(new ResaveElements([
'elementType' => $elementType,
'criteria' => [
'id' => $nodes,
'siteId' => $siteId,
'status' => null,
'enabledForSite' => false
]
]));
}
}
}

0 comments on commit fd8a7d6

Please sign in to comment.