v2-hub icon indicating copy to clipboard operation
v2-hub copied to clipboard

Localizing a slug in the CP does not update URLs.

Open jasonvarga opened this issue 5 years ago • 3 comments

Describe the bug Changing a localized slug in the CP does not update all the appropriate URLs in the Stache.

To Reproduce Steps to reproduce the behavior:

  1. Set stache_always_update: false
  2. Edit a page in the secondary locale
  3. Change the slug
  4. Using a {{ dump }} inside a nav tag, for example, notice that slug has been updated, but not url, uri, etc

Expected behavior The URLs should be updated appropriately.

Environment details:

  • Statamic Version [e.g. 2.8.12]: 2.10.3

Additional context Add any other context about the problem here.

Works fine with stache_always_update: true

cc @FrittenKeeZ

jasonvarga avatar Aug 09 '18 13:08 jasonvarga

Hi @jasonvarga,

We are facing this bug on every project, as we have a lot of multi-locale projects in Switzerland. Changing a slug in a secondary language immediately results in a 404, because the URI of such content cannot be found in the Stache. This is a serious problem for multi-locale setups and basically requires to use stache_always_update: true or clearing the cache manually. Both are not a solution for projects with a lot of content.

I invested quite some time to figure out how to solve this issue. Attached is a diff with my changes. Applying the diff should result in the following changed behaviour:

  • Uris of localized content (when changing slugs) are written into the Stache
  • Changing a localized slug of a page will also update the localized uris of children
  • The localized uris are deleted from the Stache when content gets deleted

Would it be possible to review, test and integrate these changes? I've run some basic tests and everything seems to work fine. However, I do not have enough knowledge about the Stache and thus I'm not sure if this implementation is the way to go or if it introduces other side-effects.

We really appreciate if you could find some time to solve this issue. ❤️If anyone wants to make some tests, here's the diff:

diff --git a/statamic/core/Stache/Listeners/UpdateItem.php b/statamic/core/Stache/Listeners/UpdateItem.php
index b170db59..f82067e8 100644
--- a/statamic/core/Stache/Listeners/UpdateItem.php
+++ b/statamic/core/Stache/Listeners/UpdateItem.php
@@ -2,6 +2,7 @@
 
 namespace Statamic\Stache\Listeners;
 
+use Statamic\API\Config;
 use Statamic\API\Str;
 use Statamic\API\Path;
 use Statamic\Stache\Stache;
@@ -113,8 +114,16 @@ class UpdateItem
             ->setPath($id, $path)
             ->setItem($id, $data);
 
-        if ($this->stache->driver($this->driverKey($repo))->isRoutable()) {
+        $driver = $this->stache->driver($this->driverKey($repo));
+        if ($driver->isRoutable()) {
             $this->stache->repo($repo)->setUri($id, $data->uri());
+
+            // Update localized uris in the Stache.
+            foreach (Config::getOtherLocales() as $locale) {
+                $localizedData = $this->getDataForLocale($data, $locale);
+                $localizedUri = $driver->getLocalizedUri($locale, $localizedData, $path);
+                $this->stache->repo($repo)->setUri($id, $localizedUri, $locale);
+            }
         }
 
         $this->stache->updated($this->repo());
@@ -122,6 +131,11 @@ class UpdateItem
         if ($repo === 'pages') {
             $this->updateSavedItem($data->structure());
             $this->updateChildPages($data, $original);
+
+            // Recursively update localized uris of child pages.
+            foreach (Config::getOtherLocales() as $locale) {
+                $this->updateUriOfLocalizedChildPages($data, $locale);
+            }
         }
     }
 
@@ -317,4 +331,27 @@ class UpdateItem
     {
         return (Str::contains($key, '::')) ? explode('::', $key)[0] : $key;
     }
+
+    protected function getDataForLocale(Data $data, $locale)
+    {
+        $localizedData = $data->dataForLocale($locale);
+        if (!isset($localizedData['id'])) {
+            $localizedData['id'] = $data->id();
+        }
+
+        return $localizedData;
+    }
+
+    protected function updateUriOfLocalizedChildPages(Data $data, $locale)
+    {
+        $driver = $this->stache->driver($this->driverKey('pages'));
+
+        foreach ($data->children(1) as $id => $child) {
+            $localizedData = $this->getDataForLocale($child, $locale);
+            $localizedUri = $driver->getLocalizedUri($locale, $localizedData, $child->path());
+            $this->stache->repo('pages')->setUri($id, $localizedUri, $locale);
+
+            $this->updateUriOfLocalizedChildPages($child, $locale);
+        }
+    }
 }
diff --git a/statamic/core/Stache/Repository.php b/statamic/core/Stache/Repository.php
index 10c7b71e..7376fbaa 100644
--- a/statamic/core/Stache/Repository.php
+++ b/statamic/core/Stache/Repository.php
@@ -3,6 +3,7 @@
 namespace Statamic\Stache;
 
 use Illuminate\Support\Collection;
+use Statamic\API\Config;
 use Statamic\Events\Stache\RepositoryItemInserted;
 use Statamic\Events\Stache\RepositoryItemRemoved;
 use Statamic\Events\StacheItemInserted;
@@ -273,6 +274,12 @@ class Repository
             $uris->forget($id);
         }
 
+        foreach (Config::getOtherLocales() as $locale) {
+            if ($uris = $this->uris->get($locale)) {
+                $uris->forget($id);
+            }
+        }
+
         event(new RepositoryItemRemoved($this, $id, $item));
 
         return $this;

Cheers

wanze avatar Mar 20 '20 15:03 wanze

@jasonvarga I know v2 is not your first priority, but would it be possible to get this fixed?

FrittenKeeZ avatar Feb 15 '22 09:02 FrittenKeeZ

Just had another client reporting a 404 of a page after changing the slug in the secondary language. Clearing the Stache manually solved it, but this cannot be the solution. This is a serious bug and IMHO I think this needs to be fixed. After all, Statamic 2 is still supported. Code for the fix is above. Thanks! 🙏

wanze avatar Feb 22 '22 06:02 wanze