You basically need two routes, one that picks up the original url and redirects to the new one (just in case) and another one that listens to the new pattern and then tries to find the page in the blog folder:
'routes' => [
[
'pattern' => 'blog/(:num)/(:any)',
'action' => function ($year, $slug) {
// find the page with $slug in blog folder and return if can be found
}
],
[
'pattern' => 'blog/(:any)',
'action' => function ($uid) {
$page = page('blog')->children()->find($uid);
if ( $page ) {
// get the year from the page and redirect to new folder path
return go('newPath');
}
}
]
]
Just for others who are searching for a solution to this, so here are my files:
1. Model
In the blog post model (under site/models/blog-post.php – assuming your blog post blueprint/template is blog-post.yml/.php):
class BlogPostPage extends Page {
public function url($options = null): string {
// Add date to the returned URL. Note that this is simplified as
// it is save to assume that the parent (blog) page exists.
return $this->url = $this->parent()->url() . '/' .
$this->date()->toDate('Y'). '/' . $this->uid();
}
}
2. Config/Routes
This is basically what @pixelijn has described above, but with the blanks filled for my use case. This is the config.php content:
return [
'debug' => true,
'routes' => [
[
'pattern' => 'blog/(:num)/(:any)',
'action' => function ($year, $slug) {
// find the page with $slug in blog folder and return if can be found
return page('blog/'.$slug);
}
],
[
'pattern' => 'blog/(:any)',
'action' => function ($uid) {
$page = page('blog')->children()->find($uid);
if ( $page ) {
// get the year from the page and redirect to new folder path
return go('blog/'.$page->date()->toDate('Y').'/'.$page->slug());
} else {
// If there is no page set, then go to next. This will make previews work again.
$this->next();
}
}
]
]
];
Thanks again for setting me on the right path (pun unintended!)
Update 2021-03-23: To make previews work, the second route needed an update (adding $this->next()), and I did change the preview for my blog posts to: