Moving page in page.changeStatus:after creates duplicate/ghost page

I’m trying to automatically move newly published pages into a chronological folder structure like:

/news/2026/03/my-article

Editors create drafts under /news. When publishing, the page should automatically move into /news/YYYY/MM/slug

I’m using this hook:

'page.changeStatus:after' => function ($newPage, $oldPage) {
    if ($oldPage->isDraft() && !$newPage->isDraft()) {
        $target = kirby()->site()->find('news/2026/03');

        if ($target && $newPage->parent()?->id() !== $target->id()) {
            $newPage->move($target);
        }
    }
},

The move itself works correctly.

But after publishing, I end up with:

  • /news/2026/03/my-article

  • duplicate/ghost page: /news/my-article

If I disable the hook, the ghost page does not appear.

Which Kirby 5 version exactly are you using? Are there other hooks in place as well?

Thanks for the hint. I found the same hook in the Kirby-Loop-Plugin and it’s indeed causing the ghost pages:

"page.changeStatus:after" => function (Page $newPage, Page $oldPage) {
      if ($newPage->status() === "draft") {
        KirbyLoupe::loupe()->deleteDocument($newPage->uuid()->toString());
      } elseif (
        KirbyLoupe::includePage($newPage) &&
        $oldPage->status() === "draft"
      ) {
        KirbyLoupe::indexPage($newPage);
      }
    },

Is there a way to make it compatible?